Line data Source code
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 <stdio.h>
36 : #include <string.h>
37 : #include <assert.h>
38 : #include <errno.h>
39 : #include <pthread.h>
40 : #include <fcntl.h>
41 : #include <sys/stat.h>
42 : #include <semaphore.h>
43 : #ifdef HAVE_UNISTD_H
44 : # include <unistd.h>
45 : #endif
46 : #ifndef HAVE_PSELECT
47 : # include <signal.h>
48 : #endif
49 :
50 : #include "npth.h"
51 :
52 :
53 : /* The global lock that excludes all threads but one. This is a
54 : semaphore, because these can be safely used in a library even if
55 : the application or other libraries call fork(), including from a
56 : signal handler. sem_post is async-signal-safe. (The reason a
57 : semaphore is safe and a mutex is not safe is that a mutex has an
58 : owner, while a semaphore does not.) We init sceptre to a static
59 : buffer for use by sem_init; in case sem_open is used instead
60 : SCEPTRE will changed to the value returned by sem_open. */
61 : static sem_t sceptre_buffer;
62 : static sem_t *sceptre = &sceptre_buffer;
63 :
64 : /* The main thread is the active thread at the time pth_init was
65 : called. As of now it is only useful for debugging. The volatile
66 : make sure the compiler does not eliminate this set but not used
67 : variable. */
68 : static volatile pthread_t main_thread;
69 :
70 : /* Systems that don't have pthread_mutex_timedlock get a busy wait
71 : implementation that probes the lock every BUSY_WAIT_INTERVAL
72 : milliseconds. */
73 : #define BUSY_WAIT_INTERVAL 200
74 :
75 : typedef int (*trylock_func_t) (void *);
76 :
77 : static int
78 0 : busy_wait_for (trylock_func_t trylock, void *lock,
79 : const struct timespec *abstime)
80 : {
81 : int err;
82 :
83 : /* This is not great, but better than nothing. Only works for locks
84 : which are mostly uncontested. Provides absolutely no fairness at
85 : all. Creates many wake-ups. */
86 : while (1)
87 : {
88 : struct timespec ts;
89 0 : err = npth_clock_gettime (&ts);
90 0 : if (err < 0)
91 : {
92 : /* Just for safety make sure we return some error. */
93 0 : err = errno ? errno : EINVAL;
94 0 : break;
95 : }
96 :
97 0 : if (! npth_timercmp (abstime, &ts, <))
98 : {
99 0 : err = ETIMEDOUT;
100 0 : break;
101 : }
102 :
103 0 : err = (*trylock) (lock);
104 0 : if (err != EBUSY)
105 0 : break;
106 :
107 : /* Try again after waiting a bit. We could calculate the
108 : maximum wait time from ts and abstime, but we don't
109 : bother, as our granularity is pretty fine. */
110 0 : usleep (BUSY_WAIT_INTERVAL * 1000);
111 0 : }
112 :
113 0 : return err;
114 : }
115 :
116 :
117 : static void
118 2932706 : enter_npth (void)
119 : {
120 : int res;
121 :
122 2932706 : res = sem_post (sceptre);
123 2932702 : assert (res == 0);
124 2932702 : }
125 :
126 :
127 : static void
128 2932654 : leave_npth (void)
129 : {
130 : int res;
131 2932654 : int save_errno = errno;
132 :
133 : do {
134 2932632 : res = sem_wait (sceptre);
135 2932708 : } while (res < 0 && errno == EINTR);
136 :
137 2932708 : assert (!res);
138 2932708 : errno = save_errno;
139 2932708 : }
140 :
141 : #define ENTER() enter_npth ()
142 : #define LEAVE() leave_npth ()
143 :
144 :
145 : static int
146 0 : try_sem_open (sem_t **r_sem)
147 : {
148 : sem_t *sem;
149 : char name [256];
150 0 : int counter = 0;
151 :
152 : do
153 : {
154 0 : snprintf (name, sizeof name - 1, "/npth-sceptre-%lu-%u",
155 0 : (unsigned long)getpid (), counter);
156 0 : name[sizeof name -1] = 0;
157 0 : counter++;
158 :
159 0 : sem = sem_open (name, (O_CREAT | O_EXCL), (S_IRUSR | S_IWUSR), 1);
160 0 : if (sem != SEM_FAILED)
161 : {
162 0 : *r_sem = sem;
163 0 : return 0;
164 : }
165 0 : fprintf (stderr, " semOpen(%s): %s\n", name, strerror (errno));
166 : }
167 0 : while (errno == EEXIST);
168 :
169 0 : return -1;
170 : }
171 :
172 :
173 : int
174 2 : npth_init (void)
175 : {
176 : int res;
177 :
178 2 : main_thread = pthread_self();
179 :
180 : /* Better reset ERRNO so that we know that it has been set by
181 : sem_init. */
182 2 : errno = 0;
183 :
184 : /* The semaphore is not shared and binary. */
185 2 : res = sem_init (sceptre, 0, 1);
186 2 : if (res < 0)
187 : {
188 : /* Mac OSX and some AIX versions have sem_init but return
189 : ENOSYS. This is allowed according to some POSIX versions but
190 : the informative section is quite fuzzy about it. We resort
191 : to sem_open in this case. */
192 0 : if (errno == ENOSYS)
193 : {
194 0 : if (try_sem_open (&sceptre))
195 0 : return errno;
196 : }
197 : else
198 : {
199 : /* POSIX.1-2001 defines the semaphore interface but does not
200 : specify the return value for success. Thus we better
201 : bail out on error only on a POSIX.1-2008 system. */
202 : #if _POSIX_C_SOURCE >= 200809L
203 0 : return errno;
204 : #endif
205 : }
206 : }
207 :
208 2 : LEAVE();
209 2 : return 0;
210 : }
211 :
212 :
213 : int
214 0 : npth_getname_np (npth_t target_thread, char *buf, size_t buflen)
215 : {
216 : #ifdef HAVE_PTHREAD_GETNAME_NP
217 0 : return pthread_getname_np (target_thread, buf, buflen);
218 : #else
219 : (void)target_thread;
220 : (void)buf;
221 : (void)buflen;
222 : return ENOSYS;
223 : #endif
224 : }
225 :
226 :
227 : int
228 3 : npth_setname_np (npth_t target_thread, const char *name)
229 : {
230 : #ifdef HAVE_PTHREAD_SETNAME_NP
231 : #ifdef __NetBSD__
232 : return pthread_setname_np (target_thread, "%s", (void*) name);
233 : #else
234 3 : return pthread_setname_np (target_thread, name);
235 : #endif
236 : #else
237 : (void)target_thread;
238 : (void)name;
239 : return ENOSYS;
240 : #endif
241 : }
242 :
243 :
244 :
245 : struct startup_s
246 : {
247 : void *(*start_routine) (void *);
248 : void *arg;
249 : };
250 :
251 :
252 : static void *
253 3 : thread_start (void *startup_arg)
254 : {
255 3 : struct startup_s *startup = startup_arg;
256 : void *(*start_routine) (void *);
257 : void *arg;
258 : void *result;
259 :
260 3 : start_routine = startup->start_routine;
261 3 : arg = startup->arg;
262 3 : free (startup);
263 :
264 3 : LEAVE();
265 3 : result = (*start_routine) (arg);
266 : /* Note: instead of returning here, we might end up in
267 : npth_exit() instead. */
268 3 : ENTER();
269 :
270 3 : return result;
271 : }
272 :
273 :
274 : int
275 3 : npth_create (npth_t *thread, const npth_attr_t *attr,
276 : void *(*start_routine) (void *), void *arg)
277 : {
278 : int err;
279 : struct startup_s *startup;
280 :
281 3 : startup = malloc (sizeof (*startup));
282 3 : if (!startup)
283 0 : return errno;
284 :
285 3 : startup->start_routine = start_routine;
286 3 : startup->arg = arg;
287 3 : err = pthread_create (thread, attr, thread_start, startup);
288 3 : if (err)
289 : {
290 0 : free (startup);
291 0 : return err;
292 : }
293 :
294 : /* Memory is released in thread_start. */
295 3 : return 0;
296 : }
297 :
298 :
299 : int
300 2 : npth_join (npth_t thread, void **retval)
301 : {
302 : int err;
303 :
304 : #ifdef HAVE_PTHREAD_TRYJOIN_NP
305 : /* No need to allow competing threads to enter when we can get the
306 : lock immediately. pthread_tryjoin_np is a GNU extension. */
307 2 : err = pthread_tryjoin_np (thread, retval);
308 2 : if (err != EBUSY)
309 0 : return err;
310 : #endif /*HAVE_PTHREAD_TRYJOIN_NP*/
311 :
312 2 : ENTER();
313 2 : err = pthread_join (thread, retval);
314 2 : LEAVE();
315 2 : return err;
316 : }
317 :
318 :
319 : void
320 0 : npth_exit (void *retval)
321 : {
322 0 : ENTER();
323 0 : pthread_exit (retval);
324 : /* Never reached. But just in case pthread_exit does return... */
325 : LEAVE();
326 : }
327 :
328 :
329 : int
330 21 : npth_mutex_lock (npth_mutex_t *mutex)
331 : {
332 : int err;
333 :
334 : /* No need to allow competing threads to enter when we can get the
335 : lock immediately. */
336 21 : err = pthread_mutex_trylock (mutex);
337 21 : if (err != EBUSY)
338 20 : return err;
339 :
340 1 : ENTER();
341 1 : err = pthread_mutex_lock (mutex);
342 1 : LEAVE();
343 1 : return err;
344 : }
345 :
346 :
347 : int
348 0 : npth_mutex_timedlock (npth_mutex_t *mutex, const struct timespec *abstime)
349 : {
350 : int err;
351 :
352 : /* No need to allow competing threads to enter when we can get the
353 : lock immediately. */
354 0 : err = pthread_mutex_trylock (mutex);
355 0 : if (err != EBUSY)
356 0 : return err;
357 :
358 0 : ENTER();
359 : #if HAVE_PTHREAD_MUTEX_TIMEDLOCK
360 0 : err = pthread_mutex_timedlock (mutex, abstime);
361 : #else
362 : err = busy_wait_for ((trylock_func_t) pthread_mutex_trylock, mutex, abstime);
363 : #endif
364 0 : LEAVE();
365 0 : return err;
366 : }
367 :
368 :
369 : #ifndef _NPTH_NO_RWLOCK
370 : int
371 0 : npth_rwlock_rdlock (npth_rwlock_t *rwlock)
372 : {
373 : int err;
374 :
375 : #ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
376 : /* No need to allow competing threads to enter when we can get the
377 : lock immediately. */
378 0 : err = pthread_rwlock_tryrdlock (rwlock);
379 0 : if (err != EBUSY)
380 0 : return err;
381 : #endif
382 :
383 0 : ENTER();
384 0 : err = pthread_rwlock_rdlock (rwlock);
385 0 : LEAVE();
386 0 : return err;
387 : }
388 :
389 :
390 : int
391 0 : npth_rwlock_timedrdlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
392 : {
393 : int err;
394 :
395 : #ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
396 : /* No need to allow competing threads to enter when we can get the
397 : lock immediately. */
398 0 : err = pthread_rwlock_tryrdlock (rwlock);
399 0 : if (err != EBUSY)
400 0 : return err;
401 : #endif
402 :
403 0 : ENTER();
404 : #if HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
405 0 : err = pthread_rwlock_timedrdlock (rwlock, abstime);
406 : #else
407 : err = busy_wait_for ((trylock_func_t) pthread_rwlock_tryrdlock, rwlock,
408 : abstime);
409 : #endif
410 0 : LEAVE();
411 0 : return err;
412 : }
413 :
414 :
415 : int
416 0 : npth_rwlock_wrlock (npth_rwlock_t *rwlock)
417 : {
418 : int err;
419 :
420 : #ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
421 : /* No need to allow competing threads to enter when we can get the
422 : lock immediately. */
423 0 : err = pthread_rwlock_trywrlock (rwlock);
424 0 : if (err != EBUSY)
425 0 : return err;
426 : #endif
427 :
428 0 : ENTER();
429 0 : err = pthread_rwlock_wrlock (rwlock);
430 0 : LEAVE();
431 0 : return err;
432 : }
433 :
434 :
435 : int
436 0 : npth_rwlock_timedwrlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
437 : {
438 : int err;
439 :
440 : #ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
441 : /* No need to allow competing threads to enter when we can get the
442 : lock immediately. */
443 0 : err = pthread_rwlock_trywrlock (rwlock);
444 0 : if (err != EBUSY)
445 0 : return err;
446 : #endif
447 :
448 0 : ENTER();
449 : #if HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
450 0 : err = pthread_rwlock_timedwrlock (rwlock, abstime);
451 : #elif HAVE_PTHREAD_RWLOCK_TRYRDLOCK
452 : err = busy_wait_for ((trylock_func_t) pthread_rwlock_trywrlock, rwlock,
453 : abstime);
454 : #else
455 : err = ENOSYS;
456 : #endif
457 0 : LEAVE();
458 0 : return err;
459 : }
460 : #endif
461 :
462 :
463 : int
464 0 : npth_cond_wait (npth_cond_t *cond, npth_mutex_t *mutex)
465 : {
466 : int err;
467 :
468 0 : ENTER();
469 0 : err = pthread_cond_wait (cond, mutex);
470 0 : LEAVE();
471 0 : return err;
472 : }
473 :
474 :
475 : int
476 0 : npth_cond_timedwait (npth_cond_t *cond, npth_mutex_t *mutex,
477 : const struct timespec *abstime)
478 : {
479 : int err;
480 :
481 0 : ENTER();
482 0 : err = pthread_cond_timedwait (cond, mutex, abstime);
483 0 : LEAVE();
484 0 : return err;
485 : }
486 :
487 :
488 : /* Standard POSIX Replacement API */
489 :
490 : int
491 102 : npth_usleep(unsigned int usec)
492 : {
493 : int res;
494 :
495 102 : ENTER();
496 102 : res = usleep(usec);
497 102 : LEAVE();
498 102 : return res;
499 : }
500 :
501 :
502 : unsigned int
503 2932598 : npth_sleep(unsigned int sec)
504 : {
505 : unsigned res;
506 :
507 2932598 : ENTER();
508 2932598 : res = sleep(sec);
509 2932598 : LEAVE();
510 2932598 : return res;
511 : }
512 :
513 :
514 : int
515 0 : npth_system(const char *cmd)
516 : {
517 : int res;
518 :
519 0 : ENTER();
520 0 : res = system(cmd);
521 0 : LEAVE();
522 0 : return res;
523 : }
524 :
525 :
526 : pid_t
527 0 : npth_waitpid(pid_t pid, int *status, int options)
528 : {
529 : pid_t res;
530 :
531 0 : ENTER();
532 0 : res = waitpid(pid,status, options);
533 0 : LEAVE();
534 0 : return res;
535 : }
536 :
537 :
538 : int
539 0 : npth_connect(int s, const struct sockaddr *addr, socklen_t addrlen)
540 : {
541 : int res;
542 :
543 0 : ENTER();
544 0 : res = connect(s, addr, addrlen);
545 0 : LEAVE();
546 0 : return res;
547 : }
548 :
549 :
550 : int
551 0 : npth_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
552 : {
553 : int res;
554 :
555 0 : ENTER();
556 0 : res = accept(s, addr, addrlen);
557 0 : LEAVE();
558 0 : return res;
559 : }
560 :
561 :
562 : int
563 0 : npth_select(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
564 : struct timeval *timeout)
565 : {
566 : int res;
567 :
568 0 : ENTER();
569 0 : res = select(nfd, rfds, wfds, efds, timeout);
570 0 : LEAVE();
571 0 : return res;
572 : }
573 :
574 :
575 : int
576 0 : npth_pselect(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
577 : const struct timespec *timeout, const sigset_t *sigmask)
578 : {
579 : int res;
580 :
581 0 : ENTER();
582 : #ifdef HAVE_PSELECT
583 0 : res = pselect (nfd, rfds, wfds, efds, timeout, sigmask);
584 : #else /*!HAVE_PSELECT*/
585 : {
586 : /* A better emulation of pselect would be to create a pipe, wait
587 : in the select for one end and have a signal handler write to
588 : the other end. However, this is non-trivial to implement and
589 : thus we only print a compile time warning. */
590 : # ifdef __GNUC__
591 : # warning Using a non race free pselect emulation.
592 : # endif
593 :
594 : struct timeval t, *tp;
595 :
596 : tp = NULL;
597 : if (!timeout)
598 : ;
599 : else if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000)
600 : {
601 : t.tv_sec = timeout->tv_sec;
602 : t.tv_usec = (timeout->tv_nsec + 999) / 1000;
603 : tp = &t;
604 : }
605 : else
606 : {
607 : errno = EINVAL;
608 : res = -1;
609 : goto leave;
610 : }
611 :
612 : if (sigmask)
613 : {
614 : int save_errno;
615 : sigset_t savemask;
616 :
617 : pthread_sigmask (SIG_SETMASK, sigmask, &savemask);
618 : res = select (nfd, rfds, wfds, efds, tp);
619 : save_errno = errno;
620 : pthread_sigmask (SIG_SETMASK, &savemask, NULL);
621 : errno = save_errno;
622 : }
623 : else
624 : res = select (nfd, rfds, wfds, efds, tp);
625 :
626 : leave:
627 : ;
628 : }
629 : #endif /*!HAVE_PSELECT*/
630 0 : LEAVE();
631 0 : return res;
632 : }
633 :
634 :
635 : ssize_t
636 0 : npth_read(int fd, void *buf, size_t nbytes)
637 : {
638 : ssize_t res;
639 :
640 0 : ENTER();
641 0 : res = read(fd, buf, nbytes);
642 0 : LEAVE();
643 0 : return res;
644 : }
645 :
646 :
647 : ssize_t
648 0 : npth_write(int fd, const void *buf, size_t nbytes)
649 : {
650 : ssize_t res;
651 :
652 0 : ENTER();
653 0 : res = write(fd, buf, nbytes);
654 0 : LEAVE();
655 0 : return res;
656 : }
657 :
658 :
659 : int
660 0 : npth_recvmsg (int fd, struct msghdr *msg, int flags)
661 : {
662 : int res;
663 :
664 0 : ENTER();
665 0 : res = recvmsg (fd, msg, flags);
666 0 : LEAVE();
667 0 : return res;
668 : }
669 :
670 :
671 : int
672 0 : npth_sendmsg (int fd, const struct msghdr *msg, int flags)
673 : {
674 : int res;
675 :
676 0 : ENTER();
677 0 : res = sendmsg (fd, msg, flags);
678 0 : LEAVE();
679 0 : return res;
680 : }
681 :
682 :
683 : void
684 0 : npth_unprotect (void)
685 : {
686 0 : ENTER();
687 0 : }
688 :
689 :
690 : void
691 0 : npth_protect (void)
692 : {
693 0 : LEAVE();
694 0 : }
695 :
696 :
697 : int
698 0 : npth_clock_gettime (struct timespec *ts)
699 : {
700 : #if defined(CLOCK_REALTIME) && HAVE_CLOCK_GETTIME
701 0 : return clock_gettime (CLOCK_REALTIME, ts);
702 : #elif HAVE_GETTIMEOFDAY
703 : {
704 : struct timeval tv;
705 :
706 : if (gettimeofday (&tv, NULL))
707 : return -1;
708 : ts->tv_sec = tv.tv_sec;
709 : ts->tv_nsec = tv.tv_usec * 1000;
710 : return 0;
711 : }
712 : #else
713 : /* FIXME: fall back on time() with seconds resolution. */
714 : # error clock_gettime not available - please provide a fallback.
715 : #endif
716 : }
|