1 /*
2  * Copyright (C) 1999-2005 Chris Ross
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this
9  *   list of conditions and the following disclaimer.
10  * o Redistributions in binary form must reproduce the above copyright notice,
11  *   this list of conditions and the following disclaimer in the documentation
12  *   and/or other materials provided with the distribution.
13  * o Neither the name of the ferite software nor the names of its contributors may
14  *   be used to endorse or promote products derived from this software without
15  *   specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #ifndef WIN32
36 # include <unistd.h>
37 #endif
38 #include <string.h>
39 
40 #ifndef APHEX_AS_COMPONENT
41 #include "../../../config.h"
42 #endif
43 
44 #include "aphex.h"
45 
46 /***************************************************
47  * THREAD
48  ***************************************************/
aphex_thread_create()49 AphexThread *aphex_thread_create()
50 {
51     AphexThread *thread = malloc(sizeof(AphexThread));
52     return thread;
53 }
54 
aphex_thread_destroy(AphexThread * thread)55 void aphex_thread_destroy( AphexThread *thread )
56 {
57     if( thread != NULL )
58     {
59         if( thread->running )
60           aphex_thread_stop( thread );
61         free( thread );
62     }
63 }
64 
aphex_thread_start(AphexThread * thread,void * (* start_routine)(void *),void * arg,int detach)65 int aphex_thread_start( AphexThread *thread, void *(*start_routine)(void *), void *arg, int detach )
66 {
67     int retval = 0;
68 
69     if( thread != NULL && start_routine != NULL )
70     {
71 #ifdef USE_PTHREAD
72 		thread->running = 1;
73         retval = pthread_create( &(thread->thread), NULL, start_routine, arg );
74         if( detach )
75           pthread_detach( thread->thread );
76 #endif
77         if( retval != 0 )
78         {
79             printf( "aphex: ERROR: Not enough system resources to create thread\n" );
80             return -1;
81         }
82     }
83     return 0;
84 }
85 
aphex_thread_stop(AphexThread * thread)86 void aphex_thread_stop( AphexThread *thread )
87 {
88     if( thread != NULL )
89     {
90         thread->running = 0;
91 #ifdef USE_PTHREAD
92         pthread_cancel( thread->thread );
93 #endif
94     }
95 }
96 
97 #if defined(WIN32)
usleep(int useconds)98 void usleep( int useconds )
99 {
100     if (useconds > 500)
101       sleep ((useconds+500)/1000);
102     else if (useconds > 0)
103       sleep (1);
104     else
105       sleep (0);
106 }
107 #endif
108 
aphex_thread_sleep(AphexThread * thread,int msecs)109 void aphex_thread_sleep( AphexThread *thread, int msecs )
110 {
111     usleep( msecs * 1000 );
112 }
113 
aphex_thread_join(AphexThread * thread)114 void aphex_thread_join( AphexThread *thread )
115 {
116     if( thread != NULL )
117     {
118 #ifdef USE_PTHREAD
119 		pthread_join( thread->thread, NULL );
120 #endif
121         thread->running = 0;
122     }
123 }
124 
aphex_thread_exit(AphexThread * thread,void * rval)125 void aphex_thread_exit( AphexThread *thread, void *rval )
126 {
127     if( thread != NULL )
128     {
129 #ifdef USE_PTHREAD
130 		pthread_exit( rval );
131 #endif
132         thread->running = 0;
133     }
134 }
135 
136 /***************************************************
137  * MUTEX
138  ***************************************************/
aphex_mutex_create()139 AphexMutex *aphex_mutex_create()
140 {
141     AphexMutex *mutex = malloc(sizeof(AphexMutex));
142 #ifdef USE_PTHREAD
143     pthread_mutex_init( &(mutex->mutex), NULL );
144 # if defined(USING_FAKE_RECURSIVE_MUTEX)
145     mutex->count = -1;
146     memset( &(mutex->owner), '\0', sizeof(pthread_t) );
147 # endif
148 #endif
149     mutex->recursive = 0;
150     return mutex;
151 }
152 
aphex_mutex_recursive_create()153 AphexMutex *aphex_mutex_recursive_create()
154 {
155     AphexMutex *mutex = malloc(sizeof(AphexMutex));
156 
157 #ifdef USE_PTHREAD
158 #if defined(USING_FAKE_RECURSIVE_MUTEX)
159     mutex->count = 0;
160     mutex->is_owned = 0;
161     pthread_cond_init( &mutex->cond, NULL );
162     pthread_mutex_init( &mutex->mutex, NULL );
163 #else
164     pthread_mutexattr_init( &mutex->attr );
165     pthread_mutexattr_settype( &mutex->attr, PTHREAD_MUTEX_RECURSIVE);
166     pthread_mutex_init( &mutex->mutex, &mutex->attr );
167     pthread_mutexattr_destroy( &mutex->attr );
168 #endif
169     mutex->recursive = 1;
170 #endif
171 
172     return mutex;
173 }
174 
aphex_mutex_destroy(AphexMutex * mutex)175 void aphex_mutex_destroy( AphexMutex *mutex )
176 {
177     if( mutex != NULL )
178     {
179 #ifdef USE_PTHREAD
180 #if defined(USING_FAKE_RECURSIVE_MUTEX)
181         pthread_cond_destroy( &mutex->cond );
182 #else
183 #endif
184         pthread_mutex_destroy( &mutex->mutex );
185         free( mutex );
186 #endif
187     }
188 }
189 
aphex_mutex_lock(AphexMutex * mutex)190 int aphex_mutex_lock( AphexMutex *mutex )
191 {
192 #ifdef USE_PTHREAD
193     pthread_t self = pthread_self();
194 
195     if( mutex != NULL )
196     {
197         if( pthread_mutex_lock( &mutex->mutex ) == -1 )
198           return -1;
199 
200 #if defined(USING_FAKE_RECURSIVE_MUTEX)
201         if( mutex->recursive == 1 )
202         {
203             while (1)
204             {
205                 if( pthread_equal(mutex->owner, self) )
206                 {
207                     mutex->count++;
208                     break;
209                 }
210                 else if( mutex->is_owned == 0 )
211                 {
212                     mutex->owner = self;
213                     mutex->count = 1;
214 		    mutex->is_owned = 1;
215                     break;
216                 }
217                 else
218                 {
219                     if( pthread_cond_wait( &mutex->cond, &mutex->mutex ) == -1 )
220                       return -1;
221                 }
222             }
223             pthread_mutex_unlock( &mutex->mutex );
224         }
225 #endif
226     }
227 #endif
228     return 0;
229 }
230 
aphex_mutex_unlock(AphexMutex * mutex)231 int aphex_mutex_unlock( AphexMutex *mutex )
232 {
233     if( mutex != NULL )
234     {
235 #ifdef USE_PTHREAD
236 #if defined(USING_FAKE_RECURSIVE_MUTEX)
237         if( mutex->recursive == 1 )
238         {
239             if( pthread_mutex_lock (&mutex->mutex) == -1 )
240               return -1;
241 
242             mutex->count--;
243             if( mutex->count == 0 )
244             {
245                 mutex->is_owned = 0;
246                 pthread_cond_signal( &mutex->cond );
247             }
248         }
249 #endif
250         pthread_mutex_unlock( &mutex->mutex );
251 #endif
252     }
253     return 0;
254 }
255 
256 /***************************************************
257  * EVENT
258  ***************************************************/
aphex_event_create()259 AphexEvent *aphex_event_create()
260 {
261     AphexEvent *event = malloc(sizeof(AphexEvent));
262 #ifdef USE_PTHREAD
263     if(pthread_cond_init( &(event->cond), NULL) != 0){
264         free(event);
265 	return NULL;
266     }
267     if(pthread_mutex_init( &(event->mutex), NULL ) != 0){
268         free(event);
269 	return NULL;
270     }
271 #endif
272     return event;
273 }
274 
aphex_event_destroy(AphexEvent * event)275 void aphex_event_destroy( AphexEvent *event )
276 {
277     if( event != NULL )
278     {
279 #ifdef USE_PTHREAD
280          pthread_cond_destroy( &event->cond );
281          pthread_mutex_destroy( &event->mutex );
282 #endif
283          free(event);
284     }
285 }
286 
aphex_event_signal(AphexEvent * event)287 int aphex_event_signal( AphexEvent *event )
288 {
289 #ifdef USE_PTHREAD
290     pthread_cond_signal(&(event->cond));
291 #endif
292     return 0;
293 }
294 
aphex_event_wait(AphexEvent * event)295 int aphex_event_wait( AphexEvent *event )
296 {
297 #ifdef USE_PTHREAD
298     pthread_cond_wait(&(event->cond), &(event->mutex));
299 #endif
300     return 0;
301 }
302 
303 #if defined(WIN32)
304 
305 #include <windows.h>
306 #include <time.h>
307 
308 #ifndef __GNUC__
309 #define EPOCHFILETIME (116444736000000000i64)
310 #else
311 #define EPOCHFILETIME (116444736000000000LL)
312 #endif
313 
314 struct timezone {
315     int tz_minuteswest; /* minutes W of Greenwich */
316     int tz_dsttime;     /* type of dst correction */
317 };
318 
gettimeofday(struct timeval * tv,struct timezone * tz)319 __inline int gettimeofday(struct timeval *tv, struct timezone *tz)
320 {
321     FILETIME        ft;
322     LARGE_INTEGER   li;
323     __int64         t;
324     static int      tzflag;
325 
326     if (tv)
327     {
328         GetSystemTimeAsFileTime(&ft);
329         li.LowPart  = ft.dwLowDateTime;
330         li.HighPart = ft.dwHighDateTime;
331         t  = li.QuadPart;       /* In 100-nanosecond intervals */
332         t -= EPOCHFILETIME;     /* Offset to the Epoch time */
333         t /= 10;                /* In microseconds */
334         tv->tv_sec  = (long)(t / 1000000);
335         tv->tv_usec = (long)(t % 1000000);
336     }
337 
338     if (tz)
339     {
340         if (!tzflag)
341         {
342             _tzset();
343             tzflag++;
344         }
345         tz->tz_minuteswest = _timezone / 60;
346         tz->tz_dsttime = _daylight;
347     }
348 
349     return 0;
350 }
351 
352 #endif
353 
aphex_event_timedwait(AphexEvent * event,int seconds)354 int aphex_event_timedwait( AphexEvent *event , int seconds)
355 {
356     int t_ret = 0;
357 
358 #ifdef USE_PTHREAD
359     struct timespec   ts;
360     struct timeval    tp;
361 
362     gettimeofday(&tp, NULL);
363     ts.tv_sec  = tp.tv_sec;
364     ts.tv_nsec = tp.tv_usec * 1000;
365     ts.tv_sec += seconds;
366 
367     t_ret = pthread_cond_timedwait(&(event->cond), &(event->mutex), &ts);
368 #endif
369 
370     if (t_ret != 0)
371         return 1;
372     else
373         return 0;
374 }
375