LCOV - code coverage report
Current view: top level - src - npth.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 210 29.5 %
Date: 2016-09-12 12:21:20 Functions: 10 34 29.4 %

          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     3637468 : enter_npth (void)
     145             : {
     146             :   int res;
     147             : 
     148     3637468 :   res = sem_post (sceptre);
     149     3637463 :   assert (res == 0);
     150     3637463 : }
     151             : 
     152             : 
     153             : static void
     154     3637409 : leave_npth (void)
     155             : {
     156             :   int res;
     157     3637409 :   int save_errno = errno;
     158             : 
     159             :   do {
     160     3637388 :     res = sem_wait (sceptre);
     161     3637472 :   } while (res < 0 && errno == EINTR);
     162             : 
     163     3637472 :   assert (!res);
     164     3637472 :   errno = save_errno;
     165     3637472 : }
     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     3637359 : npth_sleep(unsigned int sec)
     530             : {
     531             :   unsigned res;
     532             : 
     533     3637359 :   ENTER();
     534     3637359 :   res = sleep(sec);
     535     3637359 :   LEAVE();
     536     3637359 :   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             : }

Generated by: LCOV version 1.11