cluck 1.0.1
The cluster lock service.
cluck.cpp
Go to the documentation of this file.
1// Copyright (c) 2016-2025 Made to Order Software Corp. All Rights Reserved
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16
17// self
18//
19#include "cluck/cluck.h"
20
21#include "cluck/exception.h"
22#include "cluck/names.h"
23
24
25// eventdispatcher
26//
27#include <eventdispatcher/names.h>
28
29
30// communicator
31//
32#include <communicator/communicator_connection.h>
33#include <communicator/names.h>
34
35
36// cppthread
37//
38#include <cppthread/guard.h>
39#include <cppthread/mutex.h>
40#include <cppthread/thread.h>
41
42
43// snapdev
44//
45#include <snapdev/not_reached.h>
46
47
48// last include
49//
50#include <snapdev/poison.h>
51
52
53
88namespace cluck
89{
90
91
92
93namespace
94{
95
96
97
98cppthread::mutex g_mutex = cppthread::mutex();
103
104
105ed::match_t match_command_and_tag(ed::dispatcher_match const * m, ed::message & msg)
106{
107 if(m->f_expr != nullptr
108 && m->f_expr == msg.get_command()
109 && msg.has_parameter(g_name_cluck_param_tag)
110 && msg.get_integer_parameter(g_name_cluck_param_tag) == m->f_tag)
111 {
112 return ed::match_t::MATCH_TRUE;
113 }
114
115 return ed::match_t::MATCH_FALSE;
116}
117
118
120{
121 cppthread::guard lock(g_mutex);
122 ++g_serial;
123 if(g_serial == 0)
124 {
125 g_serial = 1; // LCOV_EXCL_LINE
126 }
127 return g_serial;
128}
129
130
131
132} // no name namespace
133
134
135
137{
138 cppthread::guard lock(g_mutex);
139 return g_lock_obtention_timeout;
140}
141
142
144{
145 if(timeout == CLUCK_DEFAULT_TIMEOUT)
146 {
148 }
149 else
150 {
151 timeout = std::clamp(timeout, CLUCK_MINIMUM_TIMEOUT, CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT);
152 }
153
154 cppthread::guard lock(g_mutex);
155 g_lock_obtention_timeout = timeout;
156}
157
158
160{
161 cppthread::guard lock(g_mutex);
162 return g_lock_duration_timeout;
163}
164
165
167{
168 if(timeout == CLUCK_DEFAULT_TIMEOUT)
169 {
171 }
172 else
173 {
174 timeout = std::clamp(timeout, CLUCK_MINIMUM_TIMEOUT, CLUCK_MAXIMUM_TIMEOUT);
175 }
176
177 cppthread::guard lock(g_mutex);
178 g_lock_duration_timeout = timeout;
179}
180
181
183{
184 cppthread::guard lock(g_mutex);
185 return g_unlock_timeout;
186}
187
188
190{
191 if(timeout == CLUCK_DEFAULT_TIMEOUT)
192 {
194 }
195 else
196 {
197 timeout = std::clamp(timeout, CLUCK_UNLOCK_MINIMUM_TIMEOUT, CLUCK_MAXIMUM_TIMEOUT);
198 }
199
200 cppthread::guard lock(g_mutex);
201 g_unlock_timeout = timeout;
202}
203
204
378 std::string const & object_name
379 , ed::connection_with_send_message::pointer_t messenger
380 , ed::dispatcher::pointer_t dispatcher
381 , mode_t mode)
382 : timer(0)
383 , f_object_name(object_name)
384 , f_tag(ed::dispatcher_match::get_next_tag())
385 , f_connection(messenger)
386 , f_dispatcher(dispatcher)
387 , f_mode(mode)
388 , f_lock_obtention_timeout(CLUCK_DEFAULT_TIMEOUT)
389 , f_lock_duration_timeout(CLUCK_DEFAULT_TIMEOUT)
390 , f_unlock_timeout(CLUCK_DEFAULT_TIMEOUT)
391{
392 if(messenger == nullptr
393 || dispatcher == nullptr)
394 {
395 throw invalid_parameter("messenger & dispatcher parameters must be defined in cluck::cluck() constructor.");
396 }
397
398 set_enable(false);
399 set_name("cluck::" + object_name);
400
401 f_connection->add_help_callback(std::bind(&cluck::help, this, std::placeholders::_1));
402}
403
404
414{
415 f_dispatcher->remove_matches(f_tag);
416}
417
418
429cluck::callback_manager_t::callback_id_t cluck::add_lock_obtained_callback(callback_t func, callback_manager_t::priority_t priority)
430{
431 return f_lock_obtained_callbacks.add_callback(func, priority);
432}
433
434
445bool cluck::remove_lock_obtained_callback(callback_manager_t::callback_id_t id)
446{
447 return f_lock_obtained_callbacks.remove_callback(id);
448}
449
450
461cluck::callback_manager_t::callback_id_t cluck::add_lock_failed_callback(callback_t func, callback_manager_t::priority_t priority)
462{
463 return f_lock_failed_callbacks.add_callback(func, priority);
464}
465
466
477bool cluck::remove_lock_failed_callback(callback_manager_t::callback_id_t id)
478{
479 return f_lock_failed_callbacks.remove_callback(id);
480}
481
482
493cluck::callback_manager_t::callback_id_t cluck::add_finally_callback(callback_t func, callback_manager_t::priority_t priority)
494{
495 return f_finally_callbacks.add_callback(func, priority);
496}
497
498
509bool cluck::remove_finally_callback(callback_manager_t::callback_id_t id)
510{
511 return f_finally_callbacks.remove_callback(id);
512}
513
514
524{
525 return f_lock_obtention_timeout;
526}
527
528
554{
555 if(timeout == CLUCK_DEFAULT_TIMEOUT)
556 {
557 f_lock_obtention_timeout = timeout;
558 }
559 else
560 {
561 f_lock_obtention_timeout = std::clamp(timeout, CLUCK_MINIMUM_TIMEOUT, CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT);
562 }
563}
564
565
578{
579 return f_lock_duration_timeout;
580}
581
582
596{
597 if(timeout == CLUCK_DEFAULT_TIMEOUT)
598 {
599 f_lock_duration_timeout = timeout;
600 }
601 else
602 {
603 f_lock_duration_timeout = std::clamp(timeout, CLUCK_MINIMUM_TIMEOUT, CLUCK_MAXIMUM_TIMEOUT);
604 }
605}
606
607
617{
618 return f_unlock_timeout;
619}
620
621
634{
635 if(timeout == CLUCK_DEFAULT_TIMEOUT)
636 {
637 f_unlock_timeout = timeout;
638 }
639 else
640 {
641 f_unlock_timeout = std::clamp(timeout, CLUCK_UNLOCK_MINIMUM_TIMEOUT, CLUCK_MAXIMUM_TIMEOUT);
642 }
643}
644
645
653std::string const & cluck::get_object_name() const
654{
655 return f_object_name;
656}
657
658
668{
669 return f_mode;
670}
671
672
683{
684 return f_type;
685}
686
687
715{
716 if(is_busy())
717 {
718 throw busy("this cluck object is busy, you cannot change its type at the moment.");
719 }
720
721 f_type = type;
722}
723
724
745{
746 return f_reason;
747}
748
749
764{
765 f_reason = reason;
766}
767
768
781bool cluck::help(advgetopt::string_set_t & commands)
782{
783 commands.insert(g_name_cluck_cmd_locked);
784 commands.insert(g_name_cluck_cmd_lock_failed);
785 commands.insert(g_name_cluck_cmd_unlocked);
786 commands.insert(g_name_cluck_cmd_unlocking);
787
788 return true;
789}
790
791
872{
873 // is lock still busy?
874 //
875 if(is_busy())
876 {
877 return false;
878 }
879
880 timeout_t obtention_timeout_date(snapdev::now());
881 if(f_lock_obtention_timeout == CLUCK_DEFAULT_TIMEOUT)
882 {
883 // use global timeout by default
884 //
885 obtention_timeout_date += ::cluck::get_lock_obtention_timeout();
886 }
887 else
888 {
889 obtention_timeout_date += f_lock_obtention_timeout;
890 }
891
892 f_serial = get_next_serial();
893
894 // send the LOCK message
895 //
896 ed::message lock_message;
897 lock_message.set_command(g_name_cluck_cmd_lock);
898 lock_message.set_service(g_name_cluck_service_name);
899 lock_message.add_parameter(g_name_cluck_param_object_name, f_object_name);
900 lock_message.add_parameter(g_name_cluck_param_tag, static_cast<int>(f_tag));
901 lock_message.add_parameter(g_name_cluck_param_pid, cppthread::gettid());
902 lock_message.add_parameter(ed::g_name_ed_param_serial, f_serial);
903 lock_message.add_parameter(g_name_cluck_param_timeout, obtention_timeout_date);
904 communicator::request_failure(lock_message);
905 if(f_lock_duration_timeout != CLUCK_DEFAULT_TIMEOUT)
906 {
907 lock_message.add_parameter(g_name_cluck_param_duration, f_lock_duration_timeout);
908 }
909 if(f_unlock_timeout != CLUCK_DEFAULT_TIMEOUT)
910 {
911 lock_message.add_parameter(g_name_cluck_param_unlock_duration, f_unlock_timeout);
912 }
914 {
915 lock_message.add_parameter(g_name_cluck_param_type, static_cast<int>(f_type));
916 }
917 if(!f_connection->send_message(lock_message))
918 {
919 // LCOV_EXCL_START
922 snapdev::NOT_REACHED_IN_TEST();
923 return false;
924 // LCOV_EXCL_STOP
925 }
926
927 set_timeout_date(obtention_timeout_date);
928 set_enable(true);
929
930 set_reason(reason_t::CLUCK_REASON_NONE);
932
933 // start listening to our messages
934 //
935 ed::dispatcher_match locked(ed::define_match(
936 ed::Expression(g_name_cluck_cmd_locked)
937 , ed::Callback(std::bind(&cluck::msg_locked, this, std::placeholders::_1))
938 , ed::MatchFunc(&match_command_and_tag)
939 , ed::Tag(f_tag)));
940 f_dispatcher->add_match(locked);
941
942 ed::dispatcher_match lock_failed(ed::define_match(
943 ed::Expression(g_name_cluck_cmd_lock_failed)
944 , ed::Callback(std::bind(&cluck::msg_lock_failed, this, std::placeholders::_1))
945 , ed::MatchFunc(&match_command_and_tag)
946 , ed::Tag(f_tag)));
947 f_dispatcher->add_match(lock_failed);
948
949 ed::dispatcher_match unlocked(ed::define_match(
950 ed::Expression(g_name_cluck_cmd_unlocked)
951 , ed::Callback(std::bind(&cluck::msg_unlocked, this, std::placeholders::_1))
952 , ed::MatchFunc(&match_command_and_tag)
953 , ed::Tag(f_tag)));
954 f_dispatcher->add_match(unlocked);
955
956 ed::dispatcher_match unlocking(ed::define_match(
957 ed::Expression(g_name_cluck_cmd_unlocking)
958 , ed::Callback(std::bind(&cluck::msg_unlocking, this, std::placeholders::_1))
959 , ed::MatchFunc(&match_command_and_tag)
960 , ed::Tag(f_tag)));
961 f_dispatcher->add_match(unlocking);
962
963 ed::dispatcher_match transmission_report(ed::define_match(
964 ed::Expression(communicator::g_name_communicator_cmd_transmission_report)
965 , ed::Callback(std::bind(&cluck::msg_transmission_report, this, std::placeholders::_1))
966 , ed::MatchFunc(&ed::one_to_one_callback_match)
967 , ed::Tag(f_tag)
968 , ed::Priority(ed::dispatcher_match::DISPATCHER_MATCH_CALLBACK_PRIORITY)));
969 f_dispatcher->add_match(transmission_report);
970
971 // we just added new commands (at least the first time) which we need to
972 // share with the communicator deamon (otherwise it won't forward them
973 // to us)
974 //
975 f_connection->send_commands();
976
977 return true;
978}
979
980
996{
997 if(f_state != state_t::CLUCK_STATE_LOCKED
998 && f_state != state_t::CLUCK_STATE_LOCKING)
999 {
1000 SNAP_LOG_NOTICE
1001 << "this cluck object is not currently locked."
1002 << SNAP_LOG_SEND;
1003 return;
1004 }
1005
1006 f_lock_timeout_date = timeout_t();
1007
1008 // explicitly send the UNLOCK message and then make sure to unregister
1009 // from the communicator; note that we do not wait for a reply to the
1010 // UNLOCK message, since to us it does not matter much as long as the
1011 // message was sent...
1012 //
1013 ed::message unlock_message;
1014 unlock_message.set_command(g_name_cluck_cmd_unlock);
1015 unlock_message.set_service(g_name_cluck_service_name);
1016 unlock_message.add_parameter(g_name_cluck_param_object_name, f_object_name);
1017 unlock_message.add_parameter(g_name_cluck_param_tag, static_cast<int>(f_tag));
1018 unlock_message.add_parameter(g_name_cluck_param_pid, gettid());
1019 unlock_message.add_parameter(ed::g_name_ed_param_serial, f_serial);
1020 if(!f_connection->send_message(unlock_message))
1021 {
1022 // LCOV_EXCL_START
1025 lock_failed();
1026 finally();
1027 snapdev::NOT_REACHED_IN_TEST();
1028 return;
1029 // LCOV_EXCL_STOP
1030 }
1031
1032 // give the UNLOCK 5 seconds to happen, if it does not happen, we'll
1033 // set the state to "failed" and still call the finally() callbacks
1034 //
1035 timeout_t unlock_timeout_date(snapdev::now());
1036 unlock_timeout_date += timeout_t(5, 0); // TODO: use correct timeout instead of hard coded 5s
1037 set_timeout_date(unlock_timeout_date);
1038 set_enable(true);
1039
1041}
1042
1043
1078{
1079 return f_lock_timeout_date;
1080}
1081
1082
1109{
1110 return f_state == state_t::CLUCK_STATE_LOCKED
1111 && f_lock_timeout_date > snapdev::now();
1112}
1113
1114
1130bool cluck::is_busy() const
1131{
1132 return f_state != state_t::CLUCK_STATE_IDLE;
1133}
1134
1135
1160bool cluck::is_cluck_msg(ed::message & msg) const
1161{
1162 // the tag must match our tag -- this allows your process to support
1163 // more than one lock (as long as each one has a different object name)
1164 //
1165 if(msg.get_integer_parameter(g_name_cluck_param_tag) != f_tag)
1166 {
1167 // IMPORTANT NOTE: this tag is checked in match_command_and_tag()
1168 // before our msg_...() callbacks get called so this
1169 // error should never happen
1170 //
1171 throw logic_error("tag mismatch in is_cluck_msg()."); // LCOV_EXCL_LINE
1172 }
1173
1174 if(msg.get_parameter(g_name_cluck_param_object_name) != f_object_name)
1175 {
1176 // somehow we received a message with the wrong object name
1177 //
1178 ed::message invalid;
1179 invalid.user_data(msg.user_data<void>());
1180 invalid.reply_to(msg);
1181 invalid.set_command(ed::g_name_ed_cmd_invalid);
1182 invalid.add_parameter(ed::g_name_ed_param_command, msg.get_command());
1183 invalid.add_parameter(
1184 ed::g_name_ed_param_message
1185 , "the \"object_name\" parameter does not match this cluck object. Got \""
1186 + msg.get_parameter("object_name")
1187 + "\", expected \""
1188 + f_object_name
1189 + "\".");
1190 f_connection->send_message(invalid);
1191 return false;
1192 }
1193
1194 return true;
1195}
1196
1197
1208{
1209 set_enable(false);
1210
1211 // the LOCK event and the lock duration can time out
1212 //
1213 switch(f_state)
1214 {
1215 // LCOV_EXCL_START
1217 SNAP_LOG_DEBUG
1218 << "process_timeout() called with state set to CLUCK_STATE_IDLE."
1219 << SNAP_LOG_SEND;
1220 snapdev::NOT_REACHED_IN_TEST();
1221 break;
1222 // LCOV_EXCL_STOP
1223
1225 // lock never obtained
1226 //
1228 lock_failed();
1229 finally();
1230 break;
1231
1233 // we are out of time, unlock now
1234 //
1236 unlock();
1237 break;
1238
1240 // the UNLOCK was never acknowledged
1241 //
1243 lock_failed();
1244 finally();
1245 break;
1246
1247 // LCOV_EXCL_START
1249 SNAP_LOG_DEBUG
1250 << "process_timeout() called with state set to CLUCK_STATE_FAILED."
1251 << SNAP_LOG_SEND;
1252 snapdev::NOT_REACHED_IN_TEST();
1253 break;
1254 // LCOV_EXCL_STOP
1255
1256 }
1257}
1258
1259
1289{
1290 f_lock_obtained_callbacks.call(this);
1291
1292 if(f_mode == mode_t::CLUCK_MODE_SIMPLE)
1293 {
1294 // in this case the user is done and we can just release the
1295 // lock automatically; otherwise the user is responsible for
1296 // releasing the lock once done
1297 //
1298 unlock();
1299 }
1300}
1301
1302
1315{
1316 if(f_state != state_t::CLUCK_STATE_FAILED)
1317 {
1319
1320 // disable our timer, we don't need to time out if the lock failed
1321 // since we're done in this case
1322 //
1323 set_enable(false);
1324
1325 f_lock_failed_callbacks.call(this);
1326 }
1327}
1328
1329
1349{
1350 f_state = state_t::CLUCK_STATE_IDLE;
1351 f_dispatcher->remove_matches(f_tag);
1352 f_finally_callbacks.call(this);
1353}
1354
1355
1367void cluck::msg_locked(ed::message & msg)
1368{
1369 if(!is_cluck_msg(msg))
1370 {
1372 lock_failed();
1373 finally();
1374 return;
1375 }
1376
1378 f_lock_timeout_date = msg.get_timespec_parameter(g_name_cluck_param_timeout_date);
1379 f_unlocked_timeout_date = msg.get_timespec_parameter(g_name_cluck_param_unlocked_date);
1380
1381 // setup our timer so it times out on that date
1382 //
1383 set_timeout_date(f_lock_timeout_date);
1384 set_enable(true);
1385
1386 lock_obtained();
1387}
1388
1389
1398void cluck::msg_lock_failed(ed::message & msg)
1399{
1400 if(!is_cluck_msg(msg))
1401 {
1403 }
1404 else
1405 {
1406 std::string const error(msg.get_parameter(g_name_cluck_param_error));
1407 if(error == g_name_cluck_value_timedout)
1408 {
1410 }
1411 else
1412 {
1413 // this may be a programmer error that need fixing
1414 //
1415 SNAP_LOG_WARNING
1416 << "communicatord did not like our LOCK message: "
1417 << error
1418 << '.'
1419 << SNAP_LOG_SEND;
1420
1422 }
1423 }
1424
1425 lock_failed();
1426 finally();
1427}
1428
1429
1450void cluck::msg_transmission_report(ed::message & msg)
1451{
1452 std::string const status(msg.get_parameter(communicator::g_name_communicator_param_status));
1453 if(msg.has_parameter(communicator::g_name_communicator_param_command)
1454 && msg.get_parameter(communicator::g_name_communicator_param_command) == g_name_cluck_cmd_lock
1455 && status == communicator::g_name_communicator_value_failed)
1456 {
1457 SNAP_LOG_RECOVERABLE_ERROR
1458 << "the transmission of our \""
1459 << msg.get_parameter(communicator::g_name_communicator_param_command)
1460 << "\" message failed to travel to a cluckd service."
1461 << SNAP_LOG_SEND;
1462
1463 // TODO: this message is global, so we fail all the
1464 // currently valid locks in this very process
1465 // (i.e. all the cluck objects have this function called
1466 // on a TRANSITION_REPORT message); this is only an issue
1467 // if you use threads and more than one has a lock at a
1468 // time
1469 //
1471 lock_failed();
1472 finally();
1473 }
1474}
1475
1476
1488void cluck::msg_unlocked(ed::message & msg)
1489{
1490 if(!is_cluck_msg(msg))
1491 {
1493 lock_failed();
1494 }
1495 else
1496 {
1497 set_enable(false);
1498 if(snapdev::now() >= f_unlocked_timeout_date)
1499 {
1500 // we took too long and received the unlocked after the lock was
1501 // over (instead of snapdev::now() called here, we may want to
1502 // call it right after the callback returned)
1503 //
1505 lock_failed();
1506 }
1507 else
1508 {
1509 set_reason(reason_t::CLUCK_REASON_NONE);
1510 }
1511 }
1512 finally();
1513}
1514
1515
1516
1529void cluck::msg_unlocking(ed::message & msg)
1530{
1531 if(!is_cluck_msg(msg))
1532 {
1534 lock_failed();
1535 finally();
1536 return;
1537 }
1538
1540 if(snapdev::now() >= f_unlocked_timeout_date)
1541 {
1542 // it looks like we are beyond unlocking this lock
1543 //
1544 set_enable(false);
1545 lock_failed();
1546 finally();
1547 }
1548 else
1549 {
1550 unlock();
1551 }
1552}
1553
1554
1555
1556} // namespace cluck
1557// vim: ts=4 sw=4 et
Cluster lock.
Definition cluck.h:121
bool help(advgetopt::string_set_t &commands)
Called whenever the HELP message is received or new messages are added.
Definition cluck.cpp:781
reason_t get_reason() const
The reason for the last failure.
Definition cluck.cpp:744
void set_lock_duration_timeout(timeout_t timeout)
Set how long inter-process locks last.
Definition cluck.cpp:595
timeout_t get_unlock_timeout() const
Retrieve the current unlock duration.
Definition cluck.cpp:616
callback_manager_t::callback_id_t add_finally_callback(callback_t func, callback_manager_t::priority_t priority=callback_manager_t::DEFAULT_PRIORITY)
Add a callback function to call when done with the lock.
Definition cluck.cpp:493
mode_t get_mode() const
Retrieve the mode.
Definition cluck.cpp:667
bool remove_finally_callback(callback_manager_t::callback_id_t id)
Remove a callback function from the lock finally list.
Definition cluck.cpp:509
void set_lock_obtention_timeout(timeout_t timeout)
Set how long to wait for an inter-process lock to take.
Definition cluck.cpp:553
bool is_busy() const
Check whether the object is currently busy.
Definition cluck.cpp:1130
void msg_lock_failed(ed::message &msg)
Process the LOCK_FAILED message.
Definition cluck.cpp:1398
timeout_t get_timeout_date() const
Get the exact time when the lock times out.
Definition cluck.cpp:1077
void msg_locked(ed::message &msg)
Process the LOCKED message.
Definition cluck.cpp:1367
void set_unlock_timeout(timeout_t timeout)
Set how long we wait on an inter-process unlock acknowledgement.
Definition cluck.cpp:633
void msg_unlocked(ed::message &msg)
Process the UNLOCK acknowledgement.
Definition cluck.cpp:1488
std::string const & get_object_name() const
Retrieve the object name.
Definition cluck.cpp:653
virtual void process_timeout() override
Process the timeout event.
Definition cluck.cpp:1207
bool lock()
Attempt a lock.
Definition cluck.cpp:871
void msg_transmission_report(ed::message &msg)
Get a transmission report on errors.
Definition cluck.cpp:1450
virtual void lock_failed()
The lock did not take or an error was reported.
Definition cluck.cpp:1314
timeout_t get_lock_duration_timeout() const
Retrieve the current lock duration.
Definition cluck.cpp:577
timeout_t get_lock_obtention_timeout() const
Retrieve the current lock obtention duration.
Definition cluck.cpp:523
callback_manager_t::callback_id_t add_lock_failed_callback(callback_t func, callback_manager_t::priority_t priority=callback_manager_t::DEFAULT_PRIORITY)
Add a callback function to call when the lock has failed.
Definition cluck.cpp:461
bool remove_lock_failed_callback(callback_manager_t::callback_id_t id)
Remove a callback function from the lock failed list.
Definition cluck.cpp:477
virtual void finally()
The lock cycle is finally complete.
Definition cluck.cpp:1348
virtual ~cluck() override
Make sure to clean up the dispatcher.
Definition cluck.cpp:413
std::uint64_t serial_t
Definition cluck.h:126
bool is_cluck_msg(ed::message &msg) const
Verify a message we received.
Definition cluck.cpp:1160
type_t get_type() const
Retrieve the lock type.
Definition cluck.cpp:682
void set_type(type_t type)
Set the lock type.
Definition cluck.cpp:714
void set_reason(reason_t reason)
Change the reason why a lock failed.
Definition cluck.cpp:763
bool remove_lock_obtained_callback(callback_manager_t::callback_id_t id)
Remove a callback function from the lock obtained list.
Definition cluck.cpp:445
void msg_unlocking(ed::message &msg)
The cluckd service sent us an UNLOCKING message.
Definition cluck.cpp:1529
virtual void lock_obtained()
This function gets called whenever the lock is in effect.
Definition cluck.cpp:1288
std::function< bool(cluck *)> callback_t
Definition cluck.h:124
bool is_locked() const
This function checks whether the lock is considered locked.
Definition cluck.cpp:1108
void unlock()
Release the inter-process lock.
Definition cluck.cpp:995
callback_manager_t::callback_id_t add_lock_obtained_callback(callback_t func, callback_manager_t::priority_t priority=callback_manager_t::DEFAULT_PRIORITY)
Add a callback function to call when the lock is obtained.
Definition cluck.cpp:429
ed::match_t match_command_and_tag(ed::dispatcher_match const *m, ed::message &msg)
Definition cluck.cpp:105
timeout_t CLUCK_UNLOCK_DEFAULT_TIMEOUT
Definition cluck.h:88
timeout_t CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT
Definition cluck.h:86
timeout_t get_unlock_timeout()
Definition cluck.cpp:182
void set_lock_duration_timeout(timeout_t timeout)
Definition cluck.cpp:166
timeout_t get_lock_obtention_timeout()
Definition cluck.cpp:136
reason_t
Definition cluck.h:44
@ CLUCK_REASON_TRANSMISSION_ERROR
timeout_t CLUCK_DEFAULT_TIMEOUT
Definition cluck.h:82
mode_t
Definition cluck.h:37
snapdev::timespec_ex timeout_t
A timeout delay.
Definition cluck.h:80
timeout_t CLUCK_LOCK_OBTENTION_DEFAULT_TIMEOUT
Definition cluck.h:85
type_t
Definition cluck.h:55
timeout_t CLUCK_UNLOCK_MINIMUM_TIMEOUT
Definition cluck.h:89
timeout_t CLUCK_MINIMUM_TIMEOUT
Definition cluck.h:83
timeout_t get_lock_duration_timeout()
Definition cluck.cpp:159
void set_lock_obtention_timeout(timeout_t timeout)
Definition cluck.cpp:143
timeout_t CLUCK_MAXIMUM_TIMEOUT
Definition cluck.h:84
void set_unlock_timeout(timeout_t timeout)
Definition cluck.cpp:189
timeout_t CLUCK_LOCK_DURATION_DEFAULT_TIMEOUT
Definition cluck.h:87

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.