2aed18ad62c55e0ddd1a39a8270c376f93e5f80d
[collectd.git] / src / libesl / esl_threadmutex.c
1 /* 
2  * Cross Platform Thread/Mutex abstraction
3  * Copyright(C) 2007 Michael Jerris
4  *
5  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
6  * copies of the Software, and permit persons to whom the Software is
7  * furnished to do so.
8  *
9  * This work is provided under this license on an "as is" basis, without warranty of any kind,
10  * either expressed or implied, including, without limitation, warranties that the covered code
11  * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
12  * risk as to the quality and performance of the covered code is with you. Should any covered
13  * code prove defective in any respect, you (not the initial developer or any other contributor)
14  * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
15  * constitutes an essential part of this license. No use of any covered code is authorized hereunder
16  * except under this disclaimer. 
17  *
18  */
19
20 #ifdef WIN32
21 /* required for TryEnterCriticalSection definition.  Must be defined before windows.h include */
22 #define _WIN32_WINNT 0x0400
23 #endif
24
25 #include "esl.h"
26 #include "esl_threadmutex.h"
27
28 #ifdef WIN32
29 #include <process.h>
30
31 #define ESL_THREAD_CALLING_CONVENTION __stdcall
32
33 struct esl_mutex {
34         CRITICAL_SECTION mutex;
35 };
36
37 #else
38
39 #include <pthread.h>
40
41 #define ESL_THREAD_CALLING_CONVENTION
42
43 struct esl_mutex {
44         pthread_mutex_t mutex;
45 };
46
47 #endif
48
49 struct esl_thread {
50 #ifdef WIN32
51         void *handle;
52 #else
53         pthread_t handle;
54 #endif
55         void *private_data;
56         esl_thread_function_t function;
57         size_t stack_size;
58 #ifndef WIN32
59         pthread_attr_t attribute;
60 #endif
61 };
62
63 size_t thread_default_stacksize = 0;
64
65 void esl_thread_override_default_stacksize(size_t size)
66 {
67         thread_default_stacksize = size;
68 }
69
70 static void * ESL_THREAD_CALLING_CONVENTION thread_launch(void *args)
71 {
72         void *exit_val;
73     esl_thread_t *thread = (esl_thread_t *)args;
74         exit_val = thread->function(thread, thread->private_data);
75 #ifndef WIN32
76         pthread_attr_destroy(&thread->attribute);
77 #endif
78         free(thread);
79
80         return exit_val;
81 }
82
83 ESL_DECLARE(esl_status_t) esl_thread_create_detached(esl_thread_function_t func, void *data)
84 {
85         return esl_thread_create_detached_ex(func, data, thread_default_stacksize);
86 }
87
88 esl_status_t esl_thread_create_detached_ex(esl_thread_function_t func, void *data, size_t stack_size)
89 {
90         esl_thread_t *thread = NULL;
91         esl_status_t status = ESL_FAIL;
92
93         if (!func || !(thread = (esl_thread_t *)malloc(sizeof(esl_thread_t)))) {
94                 goto done;
95         }
96
97         thread->private_data = data;
98         thread->function = func;
99         thread->stack_size = stack_size;
100
101 #if defined(WIN32)
102         thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
103         if (!thread->handle) {
104                 goto fail;
105         }
106         CloseHandle(thread->handle);
107
108         status = ESL_SUCCESS;
109         goto done;
110 #else
111         
112         if (pthread_attr_init(&thread->attribute) != 0) goto fail;
113
114         if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
115
116         if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
117
118         if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
119
120         status = ESL_SUCCESS;
121         goto done;
122  failpthread:
123         pthread_attr_destroy(&thread->attribute);
124 #endif
125
126  fail:
127         if (thread) {
128                 free(thread);
129         }
130  done:
131         return status;
132 }
133
134
135 ESL_DECLARE(esl_status_t) esl_mutex_create(esl_mutex_t **mutex)
136 {
137         esl_status_t status = ESL_FAIL;
138 #ifndef WIN32
139         pthread_mutexattr_t attr;
140 #endif
141         esl_mutex_t *check = NULL;
142
143         check = (esl_mutex_t *)malloc(sizeof(**mutex));
144         if (!check)
145                 goto done;
146 #ifdef WIN32
147         InitializeCriticalSection(&check->mutex);
148 #else
149         if (pthread_mutexattr_init(&attr))
150                 goto done;
151
152         if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
153                 goto fail;
154
155         if (pthread_mutex_init(&check->mutex, &attr))
156                 goto fail;
157
158         goto success;
159
160  fail:
161         pthread_mutexattr_destroy(&attr);
162         goto done;
163
164  success:
165 #endif
166         *mutex = check;
167         status = ESL_SUCCESS;
168
169  done:
170         return status;
171 }
172
173 ESL_DECLARE(esl_status_t) esl_mutex_destroy(esl_mutex_t **mutex)
174 {
175         esl_mutex_t *mp = *mutex;
176         *mutex = NULL;
177         if (!mp) {
178                 return ESL_FAIL;
179         }
180 #ifdef WIN32
181         DeleteCriticalSection(&mp->mutex);
182 #else
183         if (pthread_mutex_destroy(&mp->mutex))
184                 return ESL_FAIL;
185 #endif
186         free(mp);
187         return ESL_SUCCESS;
188 }
189
190 ESL_DECLARE(esl_status_t) esl_mutex_lock(esl_mutex_t *mutex)
191 {
192 #ifdef WIN32
193         EnterCriticalSection(&mutex->mutex);
194 #else
195         if (pthread_mutex_lock(&mutex->mutex))
196                 return ESL_FAIL;
197 #endif
198         return ESL_SUCCESS;
199 }
200
201 ESL_DECLARE(esl_status_t) esl_mutex_trylock(esl_mutex_t *mutex)
202 {
203 #ifdef WIN32
204         if (!TryEnterCriticalSection(&mutex->mutex))
205                 return ESL_FAIL;
206 #else
207         if (pthread_mutex_trylock(&mutex->mutex))
208                 return ESL_FAIL;
209 #endif
210         return ESL_SUCCESS;
211 }
212
213 ESL_DECLARE(esl_status_t) esl_mutex_unlock(esl_mutex_t *mutex)
214 {
215 #ifdef WIN32
216         LeaveCriticalSection(&mutex->mutex);
217 #else
218         if (pthread_mutex_unlock(&mutex->mutex))
219                 return ESL_FAIL;
220 #endif
221         return ESL_SUCCESS;
222 }
223
224
225
226
227
228 /* For Emacs:
229  * Local Variables:
230  * mode:c
231  * indent-tabs-mode:t
232  * tab-width:4
233  * c-basic-offset:4
234  * End:
235  * For VIM:
236  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
237  */