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