6b80fe5199931018b152fd29c75b82b40cb72b84
[yaz-moved-to-github.git] / src / mutex.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file mutex.c
8  * \brief Implements MUTEX functions
9  *
10  */
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <stddef.h>
20 #include <yaz/xmalloc.h>
21 #include <yaz/nmem.h>
22 #include <yaz/log.h>
23 #include <yaz/mutex.h>
24 #include <yaz/gettimeofday.h>
25 #ifdef WIN32
26 #include <windows.h>
27 #include <sys/timeb.h>
28 #endif
29 #include <time.h>
30
31 #if HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34
35 #if YAZ_POSIX_THREADS
36 #include <pthread.h>
37 #endif
38
39 struct yaz_mutex {
40 #ifdef WIN32
41     CRITICAL_SECTION handle;
42 #elif YAZ_POSIX_THREADS
43     pthread_mutex_t handle;
44 #endif
45     char *name;
46     int log_level;
47 };
48
49 struct yaz_cond {
50 #ifdef WIN32
51     CONDITION_VARIABLE cond;
52 #elif YAZ_POSIX_THREADS
53     pthread_cond_t cond;
54 #endif
55 };
56
57 void yaz_mutex_create(YAZ_MUTEX *p)
58 {
59     if (!*p)
60     {
61         *p = (YAZ_MUTEX) malloc(sizeof(**p));
62 #ifdef WIN32
63         InitializeCriticalSection(&(*p)->handle);
64 #elif YAZ_POSIX_THREADS
65         pthread_mutex_init(&(*p)->handle, 0);
66 #endif
67         (*p)->name = 0;
68         (*p)->log_level = 0;
69     }
70 }
71
72 void yaz_mutex_set_name(YAZ_MUTEX p, int log_level, const char *name)
73 {
74     if (p->name)
75         free(p->name);
76     p->name = 0;
77     p->log_level = 0;
78     if (name)
79     {
80         p->name = strdup(name);
81         p->log_level = log_level;
82     }
83 }
84
85 void yaz_mutex_enter(YAZ_MUTEX p)
86 {
87     if (p)
88     {
89 #ifdef WIN32
90         EnterCriticalSection(&p->handle);
91 #elif YAZ_POSIX_THREADS
92         int r = 1; /* signal : not locked (yet) */
93         
94         if (p->log_level)
95         {   /* debugging */
96             r = pthread_mutex_trylock(&p->handle);
97             if (r)
98             {
99 #if HAVE_SYS_TIME_H
100                 long long d;
101                 struct timeval tv1, tv2;
102                 gettimeofday(&tv1, 0);
103 #endif
104                 yaz_log(p->log_level,
105                         "yaz_mutex_enter: %p tid=%p name=%s waiting",
106                         p, (void *) pthread_self(), p->name);
107 #if HAVE_SYS_TIME_H
108                 r = pthread_mutex_lock(&p->handle);
109                 gettimeofday(&tv2, 0);
110                 d = 1000000LL * ((long long) tv2.tv_sec - tv1.tv_sec) +
111                     tv2.tv_usec - tv1.tv_usec;
112                 yaz_log(p->log_level, "yaz_mutex_enter: %p tid=%p name=%s "
113                         "lock delay %lld",
114                         p, (void *) pthread_self(), p->name, d);
115 #endif
116             }
117             else
118             {
119                 yaz_log(p->log_level, "yaz_mutex_enter: %p tid=%p name=%s lock",
120                         p, (void *) pthread_self(), p->name);
121             }
122         }
123         if (r)
124         {
125             r = pthread_mutex_lock(&p->handle);
126             if (p->log_level)
127             {
128                 yaz_log(p->log_level, "yaz_mutex_enter: %p tid=%p name=%s lock",
129                         p, (void *) pthread_self(), p->name);
130             }
131         }
132 #endif
133     }
134 }
135
136 void yaz_mutex_leave(YAZ_MUTEX p)
137 {
138     if (p)
139     {
140 #ifdef WIN32
141         LeaveCriticalSection(&p->handle);
142 #elif YAZ_POSIX_THREADS
143         pthread_mutex_unlock(&p->handle);
144         if (p->log_level)
145         {
146             yaz_log(p->log_level,
147                     "yaz_mutex_leave: %p tid=%p name=%s unlock",
148                     p, (void *) pthread_self(), p->name);
149         }
150 #endif
151     }
152 }
153
154 void yaz_mutex_destroy(YAZ_MUTEX *p)
155 {
156     if (*p)
157     {
158 #ifdef WIN32
159         DeleteCriticalSection(&(*p)->handle);
160 #elif YAZ_POSIX_THREADS
161         pthread_mutex_destroy(&(*p)->handle);
162 #endif
163         if ((*p)->name)
164             free((*p)->name);
165         free(*p);
166         *p = 0;
167     }
168 }
169
170
171 void yaz_cond_create(YAZ_COND *p)
172 {
173     *p = (YAZ_COND) malloc(sizeof(**p));
174 #ifdef WIN32
175     InitializeConditionVariable(&(*p)->cond);
176 #elif YAZ_POSIX_THREADS
177     pthread_cond_init(&(*p)->cond, 0);
178 #endif
179 }
180
181 void yaz_cond_destroy(YAZ_COND *p)
182 {
183     if (*p)
184     {
185 #ifdef WIN32
186 #elif YAZ_POSIX_THREADS
187         pthread_cond_destroy(&(*p)->cond);
188 #endif
189         free(*p);
190         *p = 0;
191     }
192 }
193
194 int yaz_cond_wait(YAZ_COND p, YAZ_MUTEX m, const struct timeval *abstime)
195 {
196 #ifdef WIN32
197     if (abstime)
198     {
199         struct timeval tval_now;
200         int sec, msec;
201
202         yaz_gettimeofday(&tval_now);
203
204         sec = abstime->tv_sec - tval_now.tv_sec;
205         msec = (abstime->tv_usec - tval_now.tv_usec) / 1000;
206         return SleepConditionVariableCS(&p->cond, &m->handle, sec*1000 + msec);
207     }
208     else
209         return SleepConditionVariableCS(&p->cond, &m->handle, INFINITE);
210 #elif YAZ_POSIX_THREADS
211     if (abstime)
212     {
213         struct timespec s;
214         s.tv_sec = abstime->tv_sec;
215         s.tv_nsec = abstime->tv_usec * 1000;
216         return pthread_cond_timedwait(&p->cond, &m->handle, &s);
217     }
218     else
219         return pthread_cond_wait(&p->cond, &m->handle);
220 #else
221     return -1;
222 #endif
223 }
224
225 int yaz_cond_signal(YAZ_COND p)
226 {
227 #ifdef WIN32
228     WakeConditionVariable(&p->cond);
229     return 0;
230 #elif YAZ_POSIX_THREADS
231     return pthread_cond_signal(&p->cond);
232 #else
233     return -1;
234 #endif
235 }
236
237 int yaz_cond_broadcast(YAZ_COND p)
238 {
239 #ifdef WIN32
240     WakeAllConditionVariable(&p->cond);
241     return 0;
242 #elif YAZ_POSIX_THREADS
243     return pthread_cond_broadcast(&p->cond);
244 #else
245     return -1;
246 #endif
247 }
248
249 /*
250  * Local variables:
251  * c-basic-offset: 4
252  * c-file-style: "Stroustrup"
253  * indent-tabs-mode: nil
254  * End:
255  * vim: shiftwidth=4 tabstop=8 expandtab
256  */
257