1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 
26 #include <ndb_global.h>
27 
28 #include <NdbCondition.h>
29 #include <NdbMutex.h>
30 #include <NdbMem.h>
31 
32 static int init = 0;
33 #ifdef HAVE_CLOCK_GETTIME
34 static int clock_id = CLOCK_REALTIME;
35 #endif
36 
37 void
NdbCondition_initialize(int need_monotonic)38 NdbCondition_initialize(int need_monotonic)
39 {
40 #if defined HAVE_CLOCK_GETTIME && defined HAVE_PTHREAD_CONDATTR_SETCLOCK && \
41     defined CLOCK_MONOTONIC
42 
43   int res, condattr_init = 0;
44   pthread_cond_t tmp;
45   pthread_condattr_t attr;
46 
47   init = 1;
48 
49   if (!need_monotonic)
50     return;
51 
52   if ((res = pthread_condattr_init(&attr)) != 0)
53     goto nogo;
54 
55   condattr_init = 1;
56 
57   if ((res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) != 0)
58     goto nogo;
59 
60   if ((res = pthread_cond_init(&tmp, &attr)) != 0)
61     goto nogo;
62 
63   pthread_condattr_destroy(&attr);
64   pthread_cond_destroy(&tmp);
65 
66   clock_id = CLOCK_MONOTONIC;
67 
68   return;
69 
70 nogo:
71   if (condattr_init)
72   {
73     pthread_condattr_destroy(&attr);
74   }
75 
76   clock_id = CLOCK_REALTIME;
77   fprintf(stderr,
78           "Failed to use CLOCK_MONOTONIC for pthread_condition res: %u\n",
79           res);
80   fflush(stderr);
81   return;
82 #else
83   init = 1;
84 #endif
85 }
86 
87 int
NdbCondition_Init(struct NdbCondition * ndb_cond)88 NdbCondition_Init(struct NdbCondition* ndb_cond)
89 {
90   int result;
91 
92   assert(init); /* Make sure library has been initialized */
93 
94 #if defined HAVE_CLOCK_GETTIME && defined HAVE_PTHREAD_CONDATTR_SETCLOCK && \
95     defined CLOCK_MONOTONIC
96   if (clock_id == CLOCK_MONOTONIC)
97   {
98     pthread_condattr_t attr;
99     pthread_condattr_init(&attr);
100     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
101     result = pthread_cond_init(&ndb_cond->cond, &attr);
102     pthread_condattr_destroy(&attr);
103   }
104   else
105   {
106     result = pthread_cond_init(&ndb_cond->cond, NULL);
107   }
108 #else
109   result = pthread_cond_init(&ndb_cond->cond, NULL);
110 #endif
111   assert(result==0);
112   return result;
113 }
114 
115 
116 struct NdbCondition*
NdbCondition_Create(void)117 NdbCondition_Create(void)
118 {
119   struct NdbCondition* tmpCond;
120 
121   tmpCond = (struct NdbCondition*)NdbMem_Allocate(sizeof(struct NdbCondition));
122 
123   if (tmpCond == NULL)
124     return NULL;
125 
126   (void)NdbCondition_Init(tmpCond);
127   return tmpCond;
128 }
129 
130 int
NdbCondition_Wait(struct NdbCondition * p_cond,NdbMutex * p_mutex)131 NdbCondition_Wait(struct NdbCondition* p_cond,
132                   NdbMutex* p_mutex)
133 {
134   int result;
135 
136   if (p_cond == NULL || p_mutex == NULL)
137     return 1;
138 
139 #ifdef NDB_MUTEX_STAT
140   result = pthread_cond_wait(&p_cond->cond, &p_mutex->mutex);
141 #else
142   result = pthread_cond_wait(&p_cond->cond, p_mutex);
143 #endif
144 
145   return result;
146 }
147 
148 int
NdbCondition_WaitTimeout(struct NdbCondition * p_cond,NdbMutex * p_mutex,int msecs)149 NdbCondition_WaitTimeout(struct NdbCondition* p_cond,
150                          NdbMutex* p_mutex,
151                          int msecs)
152 {
153   struct timespec abstime;
154 
155   NdbCondition_ComputeAbsTime(&abstime, msecs);
156   return NdbCondition_WaitTimeoutAbs(p_cond, p_mutex, &abstime);
157 }
158 
159 void
NdbCondition_ComputeAbsTime(struct timespec * abstime,unsigned msecs)160 NdbCondition_ComputeAbsTime(struct timespec * abstime, unsigned msecs)
161 {
162   int secs = 0;
163 #ifndef NDB_WIN
164 #ifdef HAVE_CLOCK_GETTIME
165   clock_gettime(clock_id, abstime);
166 #else
167   {
168     struct timeval tick_time;
169     gettimeofday(&tick_time, 0);
170     abstime->tv_sec  = tick_time.tv_sec;
171     abstime->tv_nsec = tick_time.tv_usec * 1000;
172   }
173 #endif
174 
175   if(msecs >= 1000){
176     secs  = msecs / 1000;
177     msecs = msecs % 1000;
178   }
179 
180   abstime->tv_sec  += secs;
181   abstime->tv_nsec += msecs * 1000000;
182   if (abstime->tv_nsec >= 1000000000) {
183     abstime->tv_sec  += 1;
184     abstime->tv_nsec -= 1000000000;
185   }
186 #else
187   set_timespec_nsec(*abstime,msecs*1000000ULL);
188 #endif
189 }
190 
191 int
NdbCondition_WaitTimeoutAbs(struct NdbCondition * p_cond,NdbMutex * p_mutex,const struct timespec * abstime)192 NdbCondition_WaitTimeoutAbs(struct NdbCondition* p_cond,
193                             NdbMutex* p_mutex,
194                             const struct timespec * abstime)
195 {
196 #ifdef NDB_WIN
197   struct timespec tmp = *abstime;
198   abstime = &tmp;
199 #endif
200 
201   if (p_cond == NULL || p_mutex == NULL)
202     return 1;
203 
204 #ifdef NDB_MUTEX_STAT
205   return pthread_cond_timedwait(&p_cond->cond, &p_mutex->mutex, abstime);
206 #else
207   return pthread_cond_timedwait(&p_cond->cond, p_mutex, abstime);
208 #endif
209 }
210 
211 int
NdbCondition_Signal(struct NdbCondition * p_cond)212 NdbCondition_Signal(struct NdbCondition* p_cond){
213   int result;
214 
215   if (p_cond == NULL)
216     return 1;
217 
218   result = pthread_cond_signal(&p_cond->cond);
219 
220   return result;
221 }
222 
223 
NdbCondition_Broadcast(struct NdbCondition * p_cond)224 int NdbCondition_Broadcast(struct NdbCondition* p_cond)
225 {
226   int result;
227 
228   if (p_cond == NULL)
229     return 1;
230 
231   result = pthread_cond_broadcast(&p_cond->cond);
232 
233   return result;
234 }
235 
236 
NdbCondition_Destroy(struct NdbCondition * p_cond)237 int NdbCondition_Destroy(struct NdbCondition* p_cond)
238 {
239   int result;
240 
241   if (p_cond == NULL)
242     return 1;
243 
244   result = pthread_cond_destroy(&p_cond->cond);
245   free(p_cond);
246 
247   return 0;
248 }
249 
250