1 /*
2   This file is part of Deadbeef Player source code
3   http://deadbeef.sourceforge.net
4 
5   pthread wrapper
6 
7   Copyright (C) 2009-2013 Alexey Yakovenko
8 
9   This software is provided 'as-is', without any express or implied
10   warranty.  In no event will the authors be held liable for any damages
11   arising from the use of this software.
12 
13   Permission is granted to anyone to use this software for any purpose,
14   including commercial applications, and to alter it and redistribute it
15   freely, subject to the following restrictions:
16 
17   1. The origin of this software must not be misrepresented; you must not
18      claim that you wrote the original software. If you use this software
19      in a product, an acknowledgment in the product documentation would be
20      appreciated but is not required.
21   2. Altered source versions must be plainly marked as such, and must not be
22      misrepresented as being the original software.
23   3. This notice may not be removed or altered from any source distribution.
24 
25   Alexey Yakovenko waker@users.sourceforge.net
26 */
27 #include <stdio.h>
28 #include <pthread.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include "threading.h"
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 
37 intptr_t
thread_start(void (* fn)(void * ctx),void * ctx)38 thread_start (void (*fn)(void *ctx), void *ctx) {
39     pthread_t tid;
40     pthread_attr_t attr;
41     int s = pthread_attr_init (&attr);
42     if (s != 0) {
43         fprintf (stderr, "pthread_attr_init failed: %s\n", strerror (s));
44         return 0;
45     }
46 
47     s = pthread_create (&tid, &attr, (void *(*)(void *))fn, (void*)ctx);
48     if (s != 0) {
49         fprintf (stderr, "pthread_create failed: %s\n", strerror (s));
50         return 0;
51     }
52     s = pthread_attr_destroy (&attr);
53     if (s != 0) {
54         fprintf (stderr, "pthread_attr_destroy failed: %s\n", strerror (s));
55         return 0;
56     }
57     return (uintptr_t)tid;
58 }
59 
60 intptr_t
thread_start_low_priority(void (* fn)(void * ctx),void * ctx)61 thread_start_low_priority (void (*fn)(void *ctx), void *ctx) {
62 #if defined(__linux__) && !defined(ANDROID)
63     pthread_t tid;
64     pthread_attr_t attr;
65     int s = pthread_attr_init (&attr);
66     if (s != 0) {
67         fprintf (stderr, "pthread_attr_init failed: %s\n", strerror (s));
68         return 0;
69     }
70 #if !STATICLINK && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 4
71     int policy;
72     s = pthread_attr_getschedpolicy (&attr, &policy);
73     if (s != 0) {
74         fprintf (stderr, "pthread_attr_getschedpolicy failed: %s\n", strerror (s));
75         return 0;
76     }
77     int minprio = sched_get_priority_min (policy);
78 #endif
79 
80     s = pthread_create (&tid, &attr, (void *(*)(void *))fn, (void*)ctx);
81     if (s != 0) {
82         fprintf (stderr, "pthread_create failed: %s\n", strerror (s));
83         return 0;
84     }
85 #if !STATICLINK && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 4
86     s = pthread_setschedprio (tid, minprio);
87     if (s != 0) {
88         fprintf (stderr, "pthread_setschedprio failed: %s\n", strerror (s));
89         pthread_cancel (tid);
90         return 0;
91     }
92 #endif
93 
94     s = pthread_attr_destroy (&attr);
95     if (s != 0) {
96         fprintf (stderr, "pthread_attr_destroy failed: %s\n", strerror (s));
97         pthread_cancel (tid);
98         return 0;
99     }
100     return tid;
101 #else
102     return thread_start (fn, ctx);
103 #endif
104 }
105 
106 int
thread_join(intptr_t tid)107 thread_join (intptr_t tid) {
108     void *retval;
109     int s = pthread_join ((pthread_t)tid, &retval);
110     if (s) {
111         fprintf (stderr, "pthread_join failed: %s\n", strerror (s));
112         return -1;
113     }
114     return 0;
115 }
116 
117 int
thread_detach(intptr_t tid)118 thread_detach (intptr_t tid) {
119     int s = pthread_detach ((pthread_t)tid);
120     if (s) {
121         fprintf (stderr, "pthread_detach failed: %s\n", strerror (s));
122         return -1;
123     }
124     return 0;
125 }
126 
127 void
thread_exit(void * retval)128 thread_exit (void *retval) {
129     pthread_exit (retval);
130 }
131 
132 uintptr_t
mutex_create_nonrecursive(void)133 mutex_create_nonrecursive (void) {
134     pthread_mutex_t *mtx = malloc (sizeof (pthread_mutex_t));
135     pthread_mutexattr_t attr = {0};
136     pthread_mutexattr_init (&attr);
137     pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
138     int err = pthread_mutex_init (mtx, &attr);
139     if (err != 0) {
140         fprintf (stderr, "pthread_mutex_init failed: %s\n", strerror (err));
141         return 0;
142     }
143     pthread_mutexattr_destroy (&attr);
144     return (uintptr_t)mtx;
145 }
146 
147 uintptr_t
mutex_create(void)148 mutex_create (void) {
149     pthread_mutex_t *mtx = malloc (sizeof (pthread_mutex_t));
150     pthread_mutexattr_t attr = {0};
151     pthread_mutexattr_init (&attr);
152     pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
153     int err = pthread_mutex_init (mtx, &attr);
154     if (err != 0) {
155         fprintf (stderr, "pthread_mutex_init failed: %s\n", strerror (err));
156         return 0;
157     }
158     pthread_mutexattr_destroy (&attr);
159     return (uintptr_t)mtx;
160 }
161 
162 void
mutex_free(uintptr_t _mtx)163 mutex_free (uintptr_t _mtx) {
164     pthread_mutex_t *mtx = (pthread_mutex_t *)_mtx;
165     pthread_mutex_destroy (mtx);
166     free (mtx);
167 }
168 
169 int
mutex_lock(uintptr_t _mtx)170 mutex_lock (uintptr_t _mtx) {
171     pthread_mutex_t *mtx = (pthread_mutex_t *)_mtx;
172     int err = pthread_mutex_lock (mtx);
173     if (err != 0) {
174         fprintf (stderr, "pthread_mutex_lock failed: %s\n", strerror (err));
175     }
176     return err;
177 }
178 
179 int
mutex_unlock(uintptr_t _mtx)180 mutex_unlock (uintptr_t _mtx) {
181     pthread_mutex_t *mtx = (pthread_mutex_t *)_mtx;
182     int err = pthread_mutex_unlock (mtx);
183     if (err != 0) {
184         fprintf (stderr, "pthread_mutex_unlock failed: %s\n", strerror (err));
185     }
186     return err;
187 }
188 
189 uintptr_t
cond_create(void)190 cond_create (void) {
191     pthread_cond_t *cond = malloc (sizeof (pthread_cond_t));
192     int err = pthread_cond_init (cond, NULL);
193     if (err != 0) {
194         fprintf (stderr, "pthread_cond_init failed: %s\n", strerror (err));
195         return 0;
196     }
197     return (uintptr_t)cond;
198 }
199 
200 void
cond_free(uintptr_t c)201 cond_free (uintptr_t c) {
202     if (c) {
203         pthread_cond_t *cond = (pthread_cond_t *)c;
204         pthread_cond_destroy (cond);
205         free (cond);
206     }
207 }
208 
209 int
cond_wait(uintptr_t c,uintptr_t m)210 cond_wait (uintptr_t c, uintptr_t m) {
211     pthread_cond_t *cond = (pthread_cond_t *)c;
212     pthread_mutex_t *mutex = (pthread_mutex_t *)m;
213     int err = mutex_lock (m);
214     if (err != 0) {
215         return err;
216     }
217     err = pthread_cond_wait (cond, mutex);
218     if (err != 0) {
219         fprintf (stderr, "pthread_cond_wait failed: %s\n", strerror (err));
220     }
221     return err;
222 }
223 
224 int
cond_signal(uintptr_t c)225 cond_signal (uintptr_t c) {
226     pthread_cond_t *cond = (pthread_cond_t *)c;
227     int err = pthread_cond_signal (cond);
228     if (err != 0) {
229         fprintf (stderr, "pthread_cond_signal failed: %s\n", strerror (err));
230     }
231     return err;
232 }
233 
234 int
cond_broadcast(uintptr_t c)235 cond_broadcast (uintptr_t c) {
236     pthread_cond_t *cond = (pthread_cond_t *)c;
237     int err = pthread_cond_broadcast (cond);
238     if (err != 0) {
239         fprintf (stderr, "pthread_cond_broadcast failed: %s\n", strerror (err));
240     }
241     return err;
242 }
243