Skip to content

Commit ec89823

Browse files
authored
Merge pull request tango-controls#641 from mliszcz/fix-511-crash-race-condition-event-push-attempt-2
Correction for race condition between polling threads and user threads pushing events. Three different data races are addressed in the PR: * All code that sets previous event value (like in below example) in attribute.cpp and eventsupplier.cpp, is protected by `event_mutex`, * We remove `detect_mutex`. Previously it was protecting the whole `EventSupplier::detect_change`. Now this method is protected by `event_mutex`, * Setting timestamps of last event subscription is protected now by `event_mutex`. Fixes tango-controls#511.
2 parents 85fbfd3 + 3bea45c commit ec89823

File tree

4 files changed

+145
-218
lines changed

4 files changed

+145
-218
lines changed

cppapi/server/attribute.cpp

Lines changed: 113 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,47 @@ static bool WantedProp_f(AttrProperty a,const char *n)
6464
return (a.get_name() == n);
6565
}
6666

67+
void LastAttrValue::store(
68+
const AttributeValue_5* attr_5,
69+
const AttributeValue_4* attr_4,
70+
const AttributeValue_3* attr_3,
71+
const AttributeValue* attr,
72+
DevFailed* error)
73+
{
74+
if (error)
75+
{
76+
except = *error;
77+
err = true;
78+
}
79+
else
80+
{
81+
if (attr_5)
82+
{
83+
quality = attr_5->quality;
84+
value_4 = attr_5->value;
85+
}
86+
else if (attr_4)
87+
{
88+
quality = attr_4->quality;
89+
value_4 = attr_4->value;
90+
}
91+
else if (attr_3)
92+
{
93+
quality = attr_3->quality;
94+
value = attr_3->value;
95+
}
96+
else if (attr)
97+
{
98+
quality = attr->quality;
99+
value = attr->value;
100+
}
101+
102+
err = false;
103+
}
104+
105+
inited = true;
106+
}
107+
67108

68109
//--------------------------------------------------------------------------------------------------------------------
69110
//
@@ -3786,9 +3827,13 @@ void Attribute::fire_change_event(DevFailed *except)
37863827
time_t change3_subscription,change4_subscription,change5_subscription;
37873828

37883829
now = time(NULL);
3789-
change3_subscription = now - event_change3_subscription;
3790-
change4_subscription = now - event_change4_subscription;
3791-
change5_subscription = now - event_change5_subscription;
3830+
3831+
{
3832+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
3833+
change3_subscription = now - event_change3_subscription;
3834+
change4_subscription = now - event_change4_subscription;
3835+
change5_subscription = now - event_change5_subscription;
3836+
}
37923837

37933838
//
37943839
// Get the event supplier(s)
@@ -4029,54 +4074,34 @@ void Attribute::fire_change_event(DevFailed *except)
40294074
bool force_change = false;
40304075
bool quality_change = false;
40314076

4032-
if ((except != NULL) ||
4033-
(quality == Tango::ATTR_INVALID) ||
4034-
((except == NULL) && (prev_change_event.err == true)) ||
4035-
((quality != Tango::ATTR_INVALID) &&
4036-
(prev_change_event.quality == Tango::ATTR_INVALID)))
40374077
{
4038-
force_change = true;
4039-
}
4078+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
40404079

4041-
std::vector<std::string> filterable_names;
4042-
std::vector<double> filterable_data;
4043-
std::vector<std::string> filterable_names_lg;
4044-
std::vector<long> filterable_data_lg;
4080+
const AttrQuality old_quality = prev_change_event.quality;
40454081

4046-
if (except != NULL)
4047-
{
4048-
prev_change_event.err = true;
4049-
prev_change_event.except = *except;
4050-
}
4051-
else
4052-
{
4053-
Tango::AttrQuality the_quality;
4054-
4055-
if (send_attr_5 != NULL)
4056-
{
4057-
the_quality = send_attr_5->quality;
4058-
prev_change_event.value_4 = send_attr_5->value;
4059-
}
4060-
else if (send_attr_4 != NULL)
4082+
if (except
4083+
|| quality == Tango::ATTR_INVALID
4084+
|| prev_change_event.err
4085+
|| old_quality == Tango::ATTR_INVALID)
40614086
{
4062-
the_quality = send_attr_4->quality;
4063-
prev_change_event.value_4 = send_attr_4->value;
4064-
}
4065-
else
4066-
{
4067-
the_quality = send_attr->quality;
4068-
prev_change_event.value = send_attr->value;
4087+
force_change = true;
40694088
}
40704089

4071-
if (prev_change_event.quality != the_quality)
4072-
{
4073-
quality_change = true;
4074-
}
4090+
prev_change_event.store(
4091+
send_attr_5,
4092+
send_attr_4,
4093+
send_attr,
4094+
Tango_nullptr,
4095+
except);
40754096

4076-
prev_change_event.quality = the_quality;
4077-
prev_change_event.err = false;
4097+
quality_change = (old_quality != prev_change_event.quality);
40784098
}
4079-
prev_change_event.inited = true;
4099+
4100+
4101+
std::vector<std::string> filterable_names;
4102+
std::vector<double> filterable_data;
4103+
std::vector<std::string> filterable_names_lg;
4104+
std::vector<long> filterable_data_lg;
40804105

40814106
filterable_names.push_back("forced_event");
40824107
if (force_change == true)
@@ -4211,9 +4236,12 @@ void Attribute::fire_archive_event(DevFailed *except)
42114236

42124237
now = time(NULL);
42134238

4214-
archive3_subscription = now - event_archive3_subscription;
4215-
archive4_subscription = now - event_archive4_subscription;
4216-
archive5_subscription = now - event_archive5_subscription;
4239+
{
4240+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
4241+
archive3_subscription = now - event_archive3_subscription;
4242+
archive4_subscription = now - event_archive4_subscription;
4243+
archive5_subscription = now - event_archive5_subscription;
4244+
}
42174245

42184246
//
42194247
// Get the event supplier(s)
@@ -4468,62 +4496,45 @@ void Attribute::fire_archive_event(DevFailed *except)
44684496
}
44694497
else
44704498
{
4471-
4472-
//
4473-
// Execute detect_change only to calculate the delta_change_rel and
4474-
// delta_change_abs and force_change !
4475-
//
4476-
44774499
bool force_change = false;
44784500
bool quality_change = false;
44794501
double delta_change_rel = 0.0;
44804502
double delta_change_abs = 0.0;
44814503

4482-
if (event_supplier_nd != NULL)
4483-
event_supplier_nd->detect_change(*this, ad,true,delta_change_rel,delta_change_abs,except,force_change,dev);
4484-
else if (event_supplier_zmq != NULL)
4485-
event_supplier_zmq->detect_change(*this, ad,true,delta_change_rel,delta_change_abs,except,force_change,dev);
4486-
4487-
4488-
std::vector<std::string> filterable_names;
4489-
std::vector<double> filterable_data;
4490-
std::vector<std::string> filterable_names_lg;
4491-
std::vector<long> filterable_data_lg;
4492-
4493-
if (except != NULL)
44944504
{
4495-
prev_archive_event.err = true;
4496-
prev_archive_event.except = *except;
4497-
}
4498-
else
4499-
{
4500-
Tango::AttrQuality the_quality;
4505+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
45014506

4502-
if (send_attr_5 != nullptr)
4503-
{
4504-
prev_archive_event.value_4 = send_attr_5->value;
4505-
the_quality = send_attr_5->quality;
4506-
}
4507-
else if (send_attr_4 != nullptr)
4508-
{
4509-
prev_archive_event.value_4 = send_attr_4->value;
4510-
the_quality = send_attr_4->quality;
4511-
}
4512-
else
4513-
{
4514-
prev_archive_event.value = send_attr->value;
4515-
the_quality = send_attr->quality;
4516-
}
4507+
// Execute detect_change only to calculate the delta_change_rel and
4508+
// delta_change_abs and force_change !
45174509

4518-
if (prev_archive_event.quality != the_quality)
4510+
if (event_supplier_nd || event_supplier_zmq)
45194511
{
4520-
quality_change = true;
4512+
EventSupplier* event_supplier = event_supplier_nd ? event_supplier_nd : event_supplier_zmq;
4513+
event_supplier->detect_change(
4514+
*this,
4515+
ad,
4516+
true,
4517+
delta_change_rel,
4518+
delta_change_abs,
4519+
except,
4520+
force_change,
4521+
dev);
45214522
}
45224523

4523-
prev_archive_event.quality = the_quality;
4524-
prev_archive_event.err = false;
4524+
prev_archive_event.store(
4525+
send_attr_5,
4526+
send_attr_4,
4527+
send_attr,
4528+
Tango_nullptr,
4529+
except);
4530+
4531+
quality_change = (old_quality != prev_archive_event.quality);
45254532
}
4526-
prev_archive_event.inited = true;
4533+
4534+
std::vector<std::string> filterable_names;
4535+
std::vector<double> filterable_data;
4536+
std::vector<std::string> filterable_names_lg;
4537+
std::vector<long> filterable_data_lg;
45274538

45284539
filterable_names.push_back("forced_event");
45294540
if (force_change == true)
@@ -4654,9 +4665,12 @@ void Attribute::fire_event(std::vector<std::string> &filt_names,std::vector<doub
46544665

46554666
now = time(NULL);
46564667

4657-
user3_subscription = now - event_user3_subscription;
4658-
user4_subscription = now - event_user4_subscription;
4659-
user5_subscription = now - event_user5_subscription;
4668+
{
4669+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
4670+
user3_subscription = now - event_user3_subscription;
4671+
user4_subscription = now - event_user4_subscription;
4672+
user5_subscription = now - event_user5_subscription;
4673+
}
46604674

46614675
//
46624676
// Get the event supplier(s)
@@ -4926,9 +4940,12 @@ void Attribute::fire_error_periodic_event(DevFailed *except)
49264940

49274941
now = time(NULL);
49284942

4929-
periodic3_subscription = now - event_periodic3_subscription;
4930-
periodic4_subscription = now - event_periodic4_subscription;
4931-
periodic5_subscription = now - event_periodic5_subscription;
4943+
{
4944+
omni_mutex_lock oml(EventSupplier::get_event_mutex());
4945+
periodic3_subscription = now - event_periodic3_subscription;
4946+
periodic4_subscription = now - event_periodic4_subscription;
4947+
periodic5_subscription = now - event_periodic5_subscription;
4948+
}
49324949

49334950
std::vector<int> client_libs = get_client_lib(PERIODIC_EVENT); // We want a copy
49344951

cppapi/server/attribute.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,21 @@ typedef union _Attr_Value
102102
}Attr_Value;
103103

104104

105-
typedef struct last_attr_value
105+
struct LastAttrValue
106106
{
107107
bool inited;
108108
Tango::AttrQuality quality;
109109
CORBA::Any value;
110110
bool err;
111111
DevFailed except;
112112
AttrValUnion value_4;
113-
} LastAttrValue;
113+
void store(
114+
const AttributeValue_5*,
115+
const AttributeValue_4*,
116+
const AttributeValue_3*,
117+
const AttributeValue*,
118+
DevFailed*);
119+
};
114120

115121
typedef enum prop_type
116122
{

0 commit comments

Comments
 (0)