1d65c3e3f124491024a2b5bdab03879eaba163ee
[npth.git] / src / npth.c
1 /* npth.c - a lightweight implementation of pth over pthread.
2    Copyright (C) 2011 g10 Code GmbH
3
4    This file is part of NPTH.
5
6    NPTH is free software; you can redistribute it and/or modify it
7    under the terms of either
8
9    - the GNU Lesser General Public License as published by the Free
10    Software Foundation; either version 3 of the License, or (at
11    your option) any later version.
12
13    or
14
15    - the GNU General Public License as published by the Free
16    Software Foundation; either version 2 of the License, or (at
17    your option) any later version.
18
19    or both in parallel, as here.
20
21    NPTH is distributed in the hope that it will be useful, but WITHOUT
22    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
24    License for more details.
25
26    You should have received a copies of the GNU General Public License
27    and the GNU Lesser General Public License along with this program;
28    if not, see <http://www.gnu.org/licenses/>.  */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <pthread.h>
38 #include <semaphore.h>
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42
43 #include "npth.h"
44
45
46 #include <stdio.h>
47 #define DEBUG_CALLS 1
48 #define _npth_debug(x, ...) printf(__VA_ARGS__)
49
50 #ifndef TEST
51 #undef  DEBUG_CALLS
52 #define DEBUG_CALLS 0
53 #undef _npth_debug
54 #define _npth_debug(x, ...)
55 #endif
56
57 /* The global lock that excludes all threads but one.  This is a
58    semaphore, because these can be safely used in a library even if
59    the application or other libraries call fork(), including from a
60    signal handler.  sem_post is async-signal-safe.  (The reason a
61    semaphore is safe and a mutex is not safe is that a mutex has an
62    owner, while a semaphore does not.)  */
63 static sem_t sceptre;
64
65 static pthread_t main_thread;
66
67 /* Systems that don't have pthread_mutex_timedlock get a busy wait
68    implementation that probes the lock every BUSY_WAIT_INTERVAL
69    milliseconds.  */
70 #define BUSY_WAIT_INTERVAL 200
71
72 typedef int (*trylock_func_t) (void *);
73
74 static int
75 busy_wait_for (trylock_func_t trylock, void *lock,
76                const struct timespec *abstime)
77 {
78   int err;
79
80   /* This is not great, but better than nothing.  Only works for locks
81      which are mostly uncontested.  Provides absolutely no fairness at
82      all.  Creates many wake-ups.  */
83   while (1)
84     {
85       struct timespec ts;
86       err = npth_clock_gettime (&ts);
87       if (err < 0)
88         {
89           /* Just for safety make sure we return some error.  */
90           err = errno ? errno : EINVAL;
91           break;
92         }
93
94       if (! npth_timercmp (abstime, &ts, <))
95         {
96           err = ETIMEDOUT;
97           break;
98         }
99
100       err = (*trylock) (lock);
101       if (err != EBUSY)
102         break;
103
104       /* Try again after waiting a bit.  We could calculate the
105          maximum wait time from ts and abstime, but we don't
106          bother, as our granularity is pretty fine.  */
107       usleep (BUSY_WAIT_INTERVAL * 1000);
108     }
109
110   return err;
111 }
112
113 \f
114 static void
115 enter_npth (const char *function)
116 {
117   int res;
118
119   if (DEBUG_CALLS)
120     _npth_debug (DEBUG_CALLS, "enter_npth (%s)\n",
121                  function ? function : "unknown");
122   res = sem_post (&sceptre);
123   assert (res == 0);
124 }
125
126
127 static void
128 leave_npth (const char *function)
129 {
130   int res;
131
132   do {
133     res = sem_wait (&sceptre);
134   } while (res < 0 && errno == EINTR);
135
136   assert (!res);
137
138   if (DEBUG_CALLS)
139     _npth_debug (DEBUG_CALLS, "leave_npth (%s)\n",
140                  function ? function : "");
141 }
142
143 #define ENTER() enter_npth(__FUNCTION__)
144 #define LEAVE() leave_npth(__FUNCTION__)
145
146 int
147 npth_init (void)
148 {
149   int res;
150
151   main_thread = pthread_self();
152
153   /* The semaphore is not shared and binary.  */
154   sem_init(&sceptre, 0, 1);
155   if (res < 0)
156
157   LEAVE();
158   return 0;
159 }
160
161
162 int
163 npth_getname_np (npth_t target_thread, char *buf, size_t buflen)
164 {
165 #ifdef HAVE_PTHREAD_GETNAME_NP
166   return pthread_getname_np (target_thread, buf, buflen);
167 #else
168   (void)target_thread;
169   (void)buf;
170   (void)buflen;
171   return ENOSYS;
172 #endif
173 }
174
175
176 int
177 npth_setname_np (npth_t target_thread, const char *name)
178 {
179 #ifdef HAVE_PTHREAD_SERNAME_NP
180   return pthread_settname_np (target_thread, name);
181 #else
182   (void)target_thread;
183   (void)name;
184   return ENOSYS;
185 #endif
186 }
187
188
189 \f
190 struct startup_s
191 {
192   void *(*start_routine) (void *);
193   void *arg;
194 };
195
196
197 static void *
198 thread_start (void *startup_arg)
199 {
200   struct startup_s *startup = startup_arg;
201   void *(*start_routine) (void *);
202   void *arg;
203   void *result;
204
205   start_routine = startup->start_routine;
206   arg = startup->arg;
207   free (startup);
208
209   LEAVE();
210   result = (*start_routine) (arg);
211   /* Note: instead of returning here, we might end up in
212      npth_exit() instead.  */
213   ENTER();
214
215   return result;
216 }
217
218
219 int
220 npth_create (npth_t *thread, const npth_attr_t *attr,
221              void *(*start_routine) (void *), void *arg)
222 {
223   int err;
224   struct startup_s *startup;
225
226   startup = malloc (sizeof (*startup));
227   if (!startup)
228     return errno;
229
230   startup->start_routine = start_routine;
231   startup->arg = arg;
232   err = pthread_create (thread, attr, thread_start, startup);
233   if (err)
234     {
235       free (startup);
236       return err;
237     }
238
239   /* Memory is released in thread_start.  */
240   return 0;
241 }
242
243
244 int
245 npth_join (npth_t thread, void **retval)
246 {
247   int err;
248
249 #ifdef HAVE_PTHREAD_TRYJOIN_NP
250   /* No need to allow competing threads to enter when we can get the
251      lock immediately.  pthread_tryjoin_np is a GNU extension.  */
252   err = pthread_tryjoin_np (thread, retval);
253   if (err != EBUSY)
254     return err;
255 #endif /*HAVE_PTHREAD_TRYJOIN_NP*/
256
257   ENTER();
258   err = pthread_join (thread, retval);
259   LEAVE();
260   return err;
261 }
262
263
264 void
265 npth_exit (void *retval)
266 {
267   ENTER();
268   pthread_exit (retval);
269   /* Never reached.  But just in case pthread_exit does return... */
270   LEAVE();
271 }
272
273 \f
274 int
275 npth_mutex_lock (npth_mutex_t *mutex)
276 {
277   int err;
278
279   /* No need to allow competing threads to enter when we can get the
280      lock immediately.  */
281   err = pthread_mutex_trylock (mutex);
282   if (err != EBUSY)
283     return err;
284
285   ENTER();
286   err = pthread_mutex_lock (mutex);
287   LEAVE();
288   return err;
289 }
290
291
292 int
293 npth_mutex_timedlock (npth_mutex_t *mutex, const struct timespec *abstime)
294 {
295   int err;
296
297   /* No need to allow competing threads to enter when we can get the
298      lock immediately.  */
299   err = pthread_mutex_trylock (mutex);
300   if (err != EBUSY)
301     return err;
302
303   ENTER();
304 #if HAVE_PTHREAD_MUTEX_TIMEDLOCK
305   err = pthread_mutex_timedlock (mutex, abstime);
306 #else
307   err = busy_wait_for ((trylock_func_t) pthread_mutex_trylock, mutex, abstime);
308 #endif
309   LEAVE();
310   return err;
311 }
312
313
314 #ifndef _NPTH_NO_RWLOCK
315 int
316 npth_rwlock_rdlock (npth_rwlock_t *rwlock)
317 {
318   int err;
319
320 #ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
321   /* No need to allow competing threads to enter when we can get the
322      lock immediately.  */
323   err = pthread_rwlock_tryrdlock (rwlock);
324   if (err != EBUSY)
325     return err;
326 #endif
327
328   ENTER();
329   err = pthread_rwlock_rdlock (rwlock);
330   LEAVE();
331   return err;
332 }
333
334
335 int
336 npth_rwlock_timedrdlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
337 {
338   int err;
339
340 #ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
341   /* No need to allow competing threads to enter when we can get the
342      lock immediately.  */
343   err = pthread_rwlock_tryrdlock (rwlock);
344   if (err != EBUSY)
345     return err;
346 #endif
347
348   ENTER();
349 #if HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
350   err = pthread_rwlock_timedrdlock (rwlock, abstime);
351 #else
352   err = busy_wait_for ((trylock_func_t) pthread_rwlock_tryrdlock, rwlock,
353                        abstime);
354 #endif
355   LEAVE();
356   return err;
357 }
358
359
360 int
361 npth_rwlock_wrlock (npth_rwlock_t *rwlock)
362 {
363   int err;
364
365 #ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
366   /* No need to allow competing threads to enter when we can get the
367      lock immediately.  */
368   err = pthread_rwlock_trywrlock (rwlock);
369   if (err != EBUSY)
370     return err;
371 #endif
372
373   ENTER();
374   err = pthread_rwlock_wrlock (rwlock);
375   LEAVE();
376   return err;
377 }
378
379
380 int
381 npth_rwlock_timedwrlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
382 {
383   int err;
384
385 #ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
386   /* No need to allow competing threads to enter when we can get the
387      lock immediately.  */
388   err = pthread_rwlock_trywrlock (rwlock);
389   if (err != EBUSY)
390     return err;
391 #endif
392
393   ENTER();
394 #if HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
395   err = pthread_rwlock_timedwrlock (rwlock, abstime);
396 #elif HAVE_PTHREAD_RWLOCK_TRYRDLOCK
397   err = busy_wait_for ((trylock_func_t) pthread_rwlock_trywrlock, rwlock,
398                        abstime);
399 #endif
400   LEAVE();
401   return err;
402 }
403 #endif
404
405
406 int
407 npth_cond_wait (npth_cond_t *cond, npth_mutex_t *mutex)
408 {
409   int err;
410
411   ENTER();
412   err = pthread_cond_wait (cond, mutex);
413   LEAVE();
414   return err;
415 }
416
417
418 int
419 npth_cond_timedwait (npth_cond_t *cond, npth_mutex_t *mutex,
420                      const struct timespec *abstime)
421 {
422   int err;
423
424   ENTER();
425   err = pthread_cond_timedwait (cond, mutex, abstime);
426   LEAVE();
427   return err;
428 }
429
430 \f
431 /* Standard POSIX Replacement API */
432
433 int
434 npth_usleep(unsigned int usec)
435 {
436   int res;
437
438   ENTER();
439   res = usleep(usec);
440   LEAVE();
441   return res;
442 }
443
444
445 unsigned int
446 npth_sleep(unsigned int sec)
447 {
448   unsigned res;
449
450   ENTER();
451   res = sleep(sec);
452   LEAVE();
453   return res;
454 }
455
456
457 int
458 npth_system(const char *cmd)
459 {
460   int res;
461
462   ENTER();
463   res = system(cmd);
464   LEAVE();
465   return res;
466 }
467
468
469 pid_t
470 npth_waitpid(pid_t pid, int *status, int options)
471 {
472   pid_t res;
473
474   ENTER();
475   res = waitpid(pid,status, options);
476   LEAVE();
477   return res;
478 }
479
480
481 int
482 npth_connect(int s, const struct sockaddr *addr, socklen_t addrlen)
483 {
484   int res;
485
486   ENTER();
487   res = connect(s, addr, addrlen);
488   LEAVE();
489   return res;
490 }
491
492
493 int
494 npth_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
495 {
496   int res;
497
498   ENTER();
499   res = accept(s, addr, addrlen);
500   LEAVE();
501   return res;
502 }
503
504
505 int
506 npth_select(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
507             struct timeval *timeout)
508 {
509   int res;
510
511   ENTER();
512   res = select(nfd, rfds, wfds, efds, timeout);
513   LEAVE();
514   return res;
515 }
516
517
518 int
519 npth_pselect(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
520              const struct timespec *timeout, const sigset_t *sigmask)
521 {
522   int res;
523
524   ENTER();
525   res = pselect(nfd, rfds, wfds, efds, timeout, sigmask);
526   LEAVE();
527   return res;
528 }
529
530
531 ssize_t
532 npth_read(int fd, void *buf, size_t nbytes)
533 {
534   ssize_t res;
535
536   ENTER();
537   res = read(fd, buf, nbytes);
538   LEAVE();
539   return res;
540 }
541
542
543 ssize_t
544 npth_write(int fd, const void *buf, size_t nbytes)
545 {
546   ssize_t res;
547
548   ENTER();
549   res = write(fd, buf, nbytes);
550   LEAVE();
551   return res;
552 }
553
554
555 int
556 npth_recvmsg (int fd, struct msghdr *msg, int flags)
557 {
558   int res;
559
560   ENTER();
561   res = recvmsg (fd, msg, flags);
562   LEAVE();
563   return res;
564 }
565
566
567 int
568 npth_sendmsg (int fd, const struct msghdr *msg, int flags)
569 {
570   int res;
571
572   ENTER();
573   res = sendmsg (fd, msg, flags);
574   LEAVE();
575   return res;
576 }
577
578
579 void
580 npth_unprotect (void)
581 {
582   ENTER();
583 }
584
585
586 void
587 npth_protect (void)
588 {
589   LEAVE();
590 }
591
592
593 int
594 npth_clock_gettime (struct timespec *ts)
595 {
596 #if HAVE_CLOCK_GETTIME
597   return clock_gettime (CLOCK_REALTIME, ts);
598 #else
599   /* FIXME: fall back on time() with seconds resolution.  */
600 # error clock_gettime not available - please provide a fallback.
601 #endif
602 }