Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
U
uniset2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UniSet project repositories
uniset2
Commits
3be517fb
Commit
3be517fb
authored
May 06, 2017
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(IOController, IONotifyController): рефакторинг работы с userdata,
а также попытка оптимизировать работу с mutex-ами в INC, правки комментариев.
parent
3338255d
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
109 additions
and
104 deletions
+109
-104
SharedMemory.cc
extensions/SharedMemory/SharedMemory.cc
+3
-8
IOController.h
include/IOController.h
+25
-2
IONotifyController.h
include/IONotifyController.h
+13
-12
IOController.cc
src/Processes/IOController.cc
+19
-1
IONotifyController.cc
src/Processes/IONotifyController.cc
+45
-63
NCRestorer.cc
src/Processes/NCRestorer.cc
+4
-18
No files found.
extensions/SharedMemory/SharedMemory.cc
View file @
3be517fb
...
...
@@ -762,15 +762,10 @@ namespace uniset
if
(
hist
.
empty
()
)
return
;
if
(
usi
->
userdata
[
udataHistory
]
==
nullptr
)
HistoryItList
*
lst
=
static_cast
<
HistoryItList
*>
(
usi
->
getUserData
(
udataHistory
));
if
(
!
lst
)
return
;
HistoryItList
&
lst
=
*
(
static_cast
<
HistoryItList
*>
(
usi
->
userdata
[
udataHistory
]));
// auto i = histmap.find(s_it->si.id);
// if( i == histmap.end() )
// return;
long
value
=
0
;
unsigned
long
sm_tv_sec
=
0
;
unsigned
long
sm_tv_nsec
=
0
;
...
...
@@ -786,7 +781,7 @@ namespace uniset
<<
" value="
<<
value
<<
endl
;
for
(
auto
&&
it1
:
lst
)
for
(
auto
&&
it1
:
(
*
lst
)
)
{
History
::
iterator
it
=
it1
;
...
...
include/IOController.h
View file @
3be517fb
...
...
@@ -33,7 +33,15 @@
//---------------------------------------------------------------------------
namespace
uniset
{
/*! Реализация интерфейса IOController-а */
/*! Реализация интерфейса IOController-а
* Важной особенностью данной реализации является то, что
* список входов/выходов (ioList) формируется один раз во время создания объекта
* и не меняется (!) в процессе работы. На этом построены некоторые оптимизации!
* Поэтому неизменность ioList во время всей жизни объекта должна гарантироваться.
* В частности, очень важной является структура USensorInfo, а также userdata,
* которые используются для "кэширования" (сохранения) указателей на специальные данные.
* (см. также IONotifyContoller).
*/
class
IOController
:
public
UniSetManager
,
public
POA_IOController_i
...
...
@@ -298,8 +306,13 @@ namespace uniset
// Дополнительные (вспомогательные поля)
uniset
::
uniset_rwmutex
val_lock
;
/*!< флаг блокирующий работу со значением */
// userdata (универасльный, небезопасный способ расширения информации связанной с датчиком)
static
const
size_t
MaxUserData
=
4
;
void
*
userdata
[
MaxUserData
]
=
{
nullptr
,
nullptr
,
nullptr
,
nullptr
};
/*!< расширение для возможности хранения своей информации */
uniset
::
uniset_rwmutex
userdata_lock
;
/*!< mutex для работы с userdata */
void
*
getUserData
(
size_t
index
);
void
setUserData
(
size_t
index
,
void
*
data
);
// сигнал для реализации механизма зависимостией..
// (все зависимые датчики подключаются к нему (см. NCRestorer::init_depends_signals)
...
...
@@ -328,7 +341,7 @@ namespace uniset
return
std
::
move
(
s
);
}
inline
uniset
::
SensorMessage
makeSensorMessage
()
inline
uniset
::
SensorMessage
makeSensorMessage
(
bool
with_lock
=
false
)
{
uniset
::
SensorMessage
sm
;
sm
.
id
=
si
.
id
;
...
...
@@ -337,6 +350,7 @@ namespace uniset
sm
.
priority
=
(
uniset
::
Message
::
Priority
)
priority
;
// лочим только изменяемые поля
if
(
with_lock
)
{
uniset
::
uniset_rwmutex_rlock
lock
(
val_lock
);
sm
.
value
=
value
;
...
...
@@ -346,6 +360,15 @@ namespace uniset
sm
.
supplier
=
supplier
;
sm
.
undefined
=
undefined
;
}
else
{
sm
.
value
=
value
;
sm
.
sm_tv
.
tv_sec
=
tv_sec
;
sm
.
sm_tv
.
tv_nsec
=
tv_nsec
;
sm
.
ci
=
ci
;
sm
.
supplier
=
supplier
;
sm
.
undefined
=
undefined
;
}
return
std
::
move
(
sm
);
}
...
...
include/IONotifyController.h
View file @
3be517fb
...
...
@@ -113,20 +113,22 @@ namespace uniset
\section sec_NC_Optimization Оптимизация работы со списком "заказчиков"
Для оптимизации поиска списка заказчиков для конкретного датчика используется поле userdata (void*) у USensorInfo!
Это опасный и "некрасивый" хак, но который
позволяет избавиться от одного лишнего поиска по unordered_map<SensorID,ConsumerList>.
Это опасный и "некрасивый" хак, но он
позволяет избавиться от одного лишнего поиска по unordered_map<SensorID,ConsumerList>.
Суть в том что к датчику через usedata мы привязываем указатель на список заказчиков. Сделано через userdata,
т.к. сам map "хранится" в IOController и IONotifyController не может поменять тип (в текущей реализации по крайней мере).
В userdata задействованы два места (см. UserDataID) для списка заказчиков и для списка порогов.
ри этом, чтобы гарантировать корректность работы, cписки заказчиков по тому или иному датчику,
создаются (см. функцию ask()), но никогда не удаляются, даже если остаются пустыми.
Это сделано, чтобы сохранённые указатели в userdata, оставались всегда валидными
(т.к. используются из разных потоков).
*/
//---------------------------------------------------------------------------
/*! \class IONotifyController
\section AskSensors Заказ датчиков
....
ConsumerMaxAttempts - максимальное число неудачных
попыток послать сообщение "заказчику". Настраивается в
конфигурационном файле. По умолчанию = 5.
*
* \section AskSensors Заказ датчиков
* ....
* \b ConsumerMaxAttempts - максимальное число неудачных попыток послать сообщение "заказчику".
* Настраивается в конфигурационном файле. По умолчанию = 5.
*/
class
IONotifyController
:
public
IOController
,
...
...
@@ -179,7 +181,7 @@ namespace uniset
ref
(
ref
),
attempt
(
maxAttemtps
)
{}
UniSetObject_i_var
ref
;
size_t
attempt
;
size_t
attempt
=
{
10
}
;
size_t
lostEvents
=
{
0
};
// количество потерянных сообщений (не смогли послать)
size_t
smCount
=
{
0
};
// количество посланных SensorMessage
...
...
@@ -283,7 +285,7 @@ namespace uniset
protected
:
IONotifyController
();
virtual
bool
activateObject
()
override
;
virtual
void
initItem
(
std
::
shared_ptr
<
USensorInfo
>&
usi
,
IOController
*
ic
);
virtual
void
initItem
(
std
::
shared_ptr
<
USensorInfo
>&
usi
,
IOController
*
ic
);
//! посылка информации об изменении состояния датчика (всем или указанному заказчику)
virtual
void
send
(
ConsumerListInfo
&
lst
,
const
uniset
::
SensorMessage
&
sm
,
const
uniset
::
ConsumerInfo
*
ci
=
nullptr
);
...
...
@@ -351,6 +353,7 @@ namespace uniset
/*! добавить новый порог для датчика */
bool
addThreshold
(
ThresholdExtList
&
lst
,
ThresholdInfoExt
&&
ti
,
const
uniset
::
ConsumerInfo
&
ci
);
/*! удалить порог для датчика */
bool
removeThreshold
(
ThresholdExtList
&
lst
,
ThresholdInfoExt
&
ti
,
const
uniset
::
ConsumerInfo
&
ci
);
...
...
@@ -380,8 +383,6 @@ namespace uniset
/*! map для хранения информации о заказчиках с которыми была потеряна связь
* и которые были удалены из списка заказчиков
* size_t - количество раз
* ObjectId - id заказчика
*/
std
::
unordered_map
<
uniset
::
ObjectId
,
LostConsumerInfo
>
lostConsumers
;
};
...
...
src/Processes/IOController.cc
View file @
3be517fb
...
...
@@ -620,7 +620,25 @@ IOController::USensorInfo::operator=(IOController_i::SensorIOInfo* r)
(
*
this
)
=
(
*
r
);
return
*
this
;
}
// ----------------------------------------------------------------------------------------
void
*
IOController
::
USensorInfo
::
getUserData
(
size_t
index
)
{
if
(
index
>
MaxUserData
)
return
nullptr
;
uniset
::
uniset_rwmutex_rlock
ulock
(
userdata_lock
);
return
userdata
[
index
];
}
void
IOController
::
USensorInfo
::
setUserData
(
size_t
index
,
void
*
data
)
{
if
(
index
>
MaxUserData
)
return
;
uniset
::
uniset_rwmutex_wrlock
ulock
(
userdata_lock
);
userdata
[
index
]
=
data
;
}
// ----------------------------------------------------------------------------------------
const
IOController
::
USensorInfo
&
IOController
::
USensorInfo
::
operator
=
(
const
IOController_i
::
SensorIOInfo
&
r
)
{
...
...
@@ -628,7 +646,7 @@ IOController::USensorInfo::operator=(const IOController_i::SensorIOInfo& r)
// any=0;
return
*
this
;
}
// ----------------------------------------------------------------------------------------
void
IOController
::
USensorInfo
::
init
(
const
IOController_i
::
SensorIOInfo
&
s
)
{
IOController
::
USensorInfo
r
(
s
);
...
...
src/Processes/IONotifyController.cc
View file @
3be517fb
...
...
@@ -513,27 +513,25 @@ void IONotifyController::askSensor(const uniset::ObjectId sid,
}
catch
(
IOController_i
::
Undefined
&
ex
)
{}
// Чтобы не было гонки между текущей функцией (askSensor)
// и setValue(), которая может происходить параллельно с этой
// держим askIOMutex до конца функции, а также для посылки пользуемся функцией send()...
{
uniset_rwmutex_wrlock
lock
(
askIOMutex
);
ask
(
askIOList
,
sid
,
ci
,
cmd
);
}
auto
usi
=
li
->
second
;
// посылка первый раз состояния
if
(
cmd
==
UniversalIO
::
UIONotify
||
(
cmd
==
UIONotifyFirstNotNull
&&
usi
->
value
)
)
{
if
(
usi
->
userdata
[
udataConsumerList
]
!=
nullptr
)
ConsumerListInfo
*
lst
=
static_cast
<
ConsumerListInfo
*>
(
usi
->
getUserData
(
udataConsumerList
));
if
(
lst
)
{
ConsumerListInfo
&
lst
=
*
(
static_cast
<
ConsumerListInfo
*>
(
usi
->
userdata
[
udataConsumerList
])
);
SensorMessage
smsg
(
std
::
move
(
usi
->
makeSensorMessage
())
);
send
(
lst
,
smsg
,
&
ci
);
uniset
::
uniset_rwmutex_rlock
lock
(
usi
->
val_lock
);
SensorMessage
smsg
(
std
::
move
(
usi
->
makeSensorMessage
(
false
))
);
send
(
*
lst
,
smsg
,
&
ci
);
}
}
}
// ------------------------------------------------------------------------------------------
void
IONotifyController
::
ask
(
AskMap
&
askLst
,
const
uniset
::
ObjectId
sid
,
const
uniset
::
ConsumerInfo
&
cons
,
UniversalIO
::
UIOCommand
cmd
)
...
...
@@ -549,20 +547,25 @@ void IONotifyController::ask( AskMap& askLst, const uniset::ObjectId sid,
{
if
(
askIterator
==
askLst
.
end
()
)
{
ConsumerListInfo
lst
;
// создаем новый список
addConsumer
(
lst
,
cons
);
// более оптимальный способ(при условии вставки первый раз)
askLst
.
emplace
(
sid
,
std
::
move
(
lst
));
ConsumerListInfo
newlst
;
// создаем новый список
addConsumer
(
newlst
,
cons
);
askLst
.
emplace
(
sid
,
std
::
move
(
newlst
));
// т.к. мы делали move
// то теперь надо достучаться до списка..
auto
i
=
askLst
.
find
(
sid
);
if
(
i
!=
askLst
.
end
()
)
{
try
{
dumpOrdersList
(
sid
,
lst
);
dumpOrdersList
(
sid
,
i
->
second
);
}
catch
(
const
uniset
::
Exception
&
ex
)
{
uwarn
<<
myname
<<
" не смогли сделать dump: "
<<
ex
<<
endl
;
}
}
}
else
{
if
(
addConsumer
(
askIterator
->
second
,
cons
)
)
...
...
@@ -629,13 +632,11 @@ void IONotifyController::ask( AskMap& askLst, const uniset::ObjectId sid,
if
(
askIterator
!=
askLst
.
end
()
)
{
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
auto
s
=
myiofind
(
sid
);
if
(
s
!=
myioEnd
()
)
s
->
second
->
userdata
[
udataConsumerList
]
=
&
(
askIterator
->
second
);
s
->
second
->
setUserData
(
udataConsumerList
,
&
(
askIterator
->
second
)
);
else
s
->
second
->
userdata
[
udataConsumerList
]
=
nullptr
;
s
->
second
->
setUserData
(
udataConsumerList
,
nullptr
)
;
}
}
// ------------------------------------------------------------------------------------------
...
...
@@ -658,7 +659,15 @@ long IONotifyController::localSetValue( std::shared_ptr<IOController::USensorInf
if
(
prevValue
==
curValue
)
return
curValue
;
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
()));
{
// с учётом того, что параллельно с этой функцией может
// выполняться askSensor, то
// посылать сообщение надо "заблокировав" доступ к value...
uniset
::
uniset_rwmutex_rlock
lock
(
usi
->
val_lock
);
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
(
false
)));
try
{
...
...
@@ -667,15 +676,9 @@ long IONotifyController::localSetValue( std::shared_ptr<IOController::USensorInf
}
catch
(...)
{}
{
uniset_rwmutex_rlock
lock
(
askIOMutex
);
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
if
(
usi
->
userdata
[
udataConsumerList
]
!=
nullptr
)
{
ConsumerListInfo
&
lst
=
*
(
static_cast
<
ConsumerListInfo
*>
(
usi
->
userdata
[
udataConsumerList
]));
send
(
lst
,
sm
);
}
ConsumerListInfo
*
lst
=
static_cast
<
ConsumerListInfo
*>
(
usi
->
getUserData
(
udataConsumerList
));
if
(
lst
)
send
(
*
lst
,
sm
);
}
// проверка порогов
...
...
@@ -789,7 +792,7 @@ void IONotifyController::send( ConsumerListInfo& lst, const uniset::SensorMessag
// --------------------------------------------------------------------------------------------------------------
bool
IONotifyController
::
activateObject
()
{
// сперва
вычитаем датчиков
и заказчиков..
// сперва
загружаем датчики
и заказчиков..
readDump
();
// а потом уже собственно активация..
return
IOController
::
activateObject
();
...
...
@@ -805,9 +808,8 @@ void IONotifyController::readDump()
catch
(
const
std
::
exception
&
ex
)
{
// Если дамп не удалось считать, значит что-то не то в configure.xml
// и безопаснее "вылететь", чем запустится,
но половина датчиков работать не будет
// и безопаснее "вылететь", чем запустится,
т.к. часть датчиков не будет работать
// как ожидается.
ucrit
<<
myname
<<
"(IONotifyController::readDump): "
<<
ex
.
what
()
<<
endl
;
std
::
terminate
();
// std::abort();
}
...
...
@@ -991,15 +993,9 @@ void IONotifyController::askThreshold(uniset::ObjectId sid, const uniset::Consum
it
=
askTMap
.
find
(
sid
);
if
(
li
!=
myioEnd
()
)
{
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
if
(
it
==
askTMap
.
end
()
)
li
->
second
->
userdata
[
udataThresholdList
]
=
nullptr
;
else
li
->
second
->
userdata
[
udataThresholdList
]
=
(
void
*
)(
&
(
it
->
second
));
}
li
->
second
->
setUserData
(
udataThresholdList
,
&
(
it
->
second
));
}
// unlock
}
// unlock trshMutex
}
// --------------------------------------------------------------------------------------------------------------
bool
IONotifyController
::
addThreshold
(
ThresholdExtList
&
lst
,
ThresholdInfoExt
&&
ti
,
const
uniset
::
ConsumerInfo
&
ci
)
...
...
@@ -1063,24 +1059,17 @@ void IONotifyController::checkThreshold( IOController::IOStateList::iterator& li
// --------------------------------------------------------------------------------------------------------------
void
IONotifyController
::
checkThreshold
(
std
::
shared_ptr
<
IOController
::
USensorInfo
>&
usi
,
bool
send_msg
)
{
// поиск списка порогов
ThresholdsListInfo
*
ti
=
nullptr
;
{
uniset_rwmutex_rlock
lock
(
trshMutex
);
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
if
(
usi
->
userdata
[
udataThresholdList
]
==
nullptr
)
ThresholdsListInfo
*
ti
=
static_cast
<
ThresholdsListInfo
*>
(
usi
->
getUserData
(
udataThresholdList
));
if
(
!
ti
||
ti
->
list
.
empty
()
)
return
;
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
ti
=
static_cast
<
ThresholdsListInfo
*>
(
usi
->
userdata
[
udataThresholdList
]);
// обрабатываем текущее состояние датчика обязательно "залочив" значение..
if
(
ti
->
list
.
empty
()
)
return
;
}
uniset_rwmutex_rlock
vlock
(
usi
->
val_lock
);
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
()));
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
(
false
)));
// текущее время
struct
timespec
tm
=
uniset
::
now_to_timespec
();
...
...
@@ -1316,7 +1305,8 @@ IONotifyController_i::ThresholdsListSeq* IONotifyController::getThresholdsList()
// -----------------------------------------------------------------------------
void
IONotifyController
::
onChangeUndefinedState
(
std
::
shared_ptr
<
USensorInfo
>&
usi
,
IOController
*
ic
)
{
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
())
);
uniset_rwmutex_rlock
vlock
(
usi
->
val_lock
);
SensorMessage
sm
(
std
::
move
(
usi
->
makeSensorMessage
(
false
))
);
try
{
...
...
@@ -1325,17 +1315,9 @@ void IONotifyController::onChangeUndefinedState( std::shared_ptr<USensorInfo>& u
}
catch
(...)
{}
{
// lock
uniset_rwmutex_rlock
lock
(
askIOMutex
);
//! \warning Оптимизация использует userdata! Это опасно, если кто-то ещё захочет его использовать!
if
(
usi
->
userdata
[
udataConsumerList
]
!=
nullptr
)
{
ConsumerListInfo
&
lst
=
*
(
static_cast
<
ConsumerListInfo
*>
(
usi
->
userdata
[
udataConsumerList
]));
send
(
lst
,
sm
);
}
}
// unlock
ConsumerListInfo
*
lst
=
static_cast
<
ConsumerListInfo
*>
(
usi
->
getUserData
(
udataConsumerList
));
if
(
lst
)
send
(
*
lst
,
sm
);
}
// -----------------------------------------------------------------------------
...
...
src/Processes/NCRestorer.cc
View file @
3be517fb
...
...
@@ -75,7 +75,7 @@ void NCRestorer::addlist( IONotifyController* ic, std::shared_ptr<IOController::
case
UniversalIO
:
:
AO
:
{
ic
->
askIOList
[
inf
->
si
.
id
]
=
std
::
move
(
lst
);
inf
->
userdata
[
IONotifyController
::
udataConsumerList
]
=
&
(
ic
->
askIOList
[
inf
->
si
.
id
]
);
inf
->
setUserData
(
IONotifyController
::
udataConsumerList
,
&
(
ic
->
askIOList
[
inf
->
si
.
id
])
);
break
;
}
...
...
@@ -151,29 +151,15 @@ NCRestorer::SInfo& NCRestorer::SInfo::operator=( const IOController_i::SensorIOI
this
->
blocked
=
inf
.
blocked
;
this
->
dbignore
=
inf
.
dbignore
;
{
uniset_rwmutex_wrlock
l
(
this
->
userdata_lock
);
for
(
size_t
i
=
0
;
i
<
IOController
::
USensorInfo
::
MaxUserData
;
i
++
)
this
->
userdata
[
i
]
=
nullptr
;
}
return
*
this
;
}
// ------------------------------------------------------------------------------------------
#if 0
NCRestorer::SInfo& NCRestorer::SInfo::operator=( const std::shared_ptr<IOController_i::SensorIOInfo>& inf )
{
this->si = inf->si;
this->type = inf->type;
this->priority = inf->priority;
this->default_val = inf->default_val;
this->real_value = inf->real_value;
this->ci = inf->ci;
this->undefined = inf->undefined;
this->blocked = inf->blocked;
this->dbignore = inf->dbignore;
this->any = 0;
return *this;
}
#endif
// ------------------------------------------------------------------------------------------
void
NCRestorer
::
init_depends_signals
(
IONotifyController
*
ic
)
{
for
(
auto
it
=
ic
->
ioList
.
begin
();
it
!=
ic
->
ioList
.
end
();
++
it
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment