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