1 #ifndef SYNCOBJ__HPP
2 #define SYNCOBJ__HPP
3 
4 /*  $Id: SyncObj.hpp 573341 2018-10-25 17:53:05Z saprykin $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Authors: Dmitri Dmitrienko
30  *
31  * File Description:
32  *
33  *  Synchronization classes and utilities
34  *
35  */
36 
37 #include <atomic>
38 #include <thread>
39 #include <signal.h>
40 #include <functional>
41 
42 #include <corelib/ncbithr.hpp>
43 
44 #include "IdCassScope.hpp"
45 
46 
47 BEGIN_IDBLOB_SCOPE
48 USING_NCBI_SCOPE;
49 
50 bool WaitCondVar(unsigned int  timeoutmks, CFastMutex &  mtx,
51                  CConditionVariable &  ev,
52                  const function<bool()> &  is_done_cb,
53                  const function<void(bool*)> &  update_rslt_cb);
54 
55 
56 #ifdef __linux__
57 class CFutex
58 {
59 public:
60     enum EWaitResult {
61         eWaitResultTimeOut, // value hasn't changed
62         eWaitResultOk,      // value is changed and we waited
63         eWaitResultOkFast   // value is changed but we didn't wait
64     };
65 
66     void DoWake(int waiters = INT_MAX);
67 
68 public:
CFutex(int start=0)69     CFutex(int start = 0) :
70         m_Value(start)
71     {}
72 
73     CFutex& operator=(const CFutex&) = delete;
74     CFutex(const CFutex&) = delete;
75 
CompareExchange(int expected,int replace_with,bool wake_others=true)76     bool CompareExchange(int expected, int replace_with,
77                          bool wake_others = true)
78     {
79         bool    rv = m_Value.compare_exchange_weak(expected, replace_with,
80                                                    memory_order_relaxed);
81         if (rv && wake_others)
82             DoWake();
83         return rv;
84     }
85 
Value(void)86     int Value(void)
87     {
88         return m_Value;
89     }
90 
91     EWaitResult WaitWhile(int value, int timeout_mks = -1);
92 
Wake(void)93     void Wake(void)
94     {
95         DoWake();
96     }
97 
Set(int value,bool wake_others=true)98     int Set(int value, bool wake_others = true)
99     {
100         int rv = m_Value.exchange(value);
101         if ((rv != value) && wake_others)
102             DoWake();
103         return rv;
104     }
105 
Inc(bool wake_others=true)106     int Inc(bool wake_others = true)
107     {
108         int rv = atomic_fetch_add(&m_Value, 1);
109         if (wake_others)
110             DoWake();
111         return rv;
112     }
113 
Dec(bool wake_others=true)114     int Dec(bool wake_others = true)
115     {
116         int     rv = atomic_fetch_sub(&m_Value, 1);
117         if (wake_others)
118             DoWake();
119         return rv;
120     }
121 
SemInc(void)122     int SemInc(void)
123     {
124         int     rv = atomic_fetch_add(&m_Value, 1);
125         return rv;
126     }
127 
SemDec(void)128     int SemDec(void)
129     {
130         int     rv = atomic_fetch_sub(&m_Value, 1);
131         if (rv < 0)
132             DoWake();
133         return rv;
134     }
135 
136 private:
137     volatile atomic_int     m_Value;
138 };
139 #endif
140 
141 
142 class SSignalHandler
143 {
144 public:
s_CtrlCPressed(void)145     static bool s_CtrlCPressed(void)
146     {
147         return sm_CtrlCPressed != 0;
148     }
149 
150     static void s_WatchCtrlCPressed(bool  enable,
151                                     function<void()> on_ctrl_c_pressed = NULL);
152 
153 private:
154     static volatile sig_atomic_t                        sm_CtrlCPressed;
155 #ifdef __linux__
156     static CFutex                                       sm_CtrlCPressedEvent;
157 #endif
158     static unique_ptr<thread, function<void(thread*)> > sm_WatchThread;
159     static function<void()>                             sm_OnCtrlCPressed;
160     static volatile bool                                sm_Quit;
161 };
162 
163 
164 END_IDBLOB_SCOPE
165 
166 #endif
167