github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/thread-sema.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "config.h"
     6  #include "runtime.h"
     7  
     8  #include <errno.h>
     9  #include <stdlib.h>
    10  #include <time.h>
    11  #include <semaphore.h>
    12  
    13  /* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
    14     We don't always use condition variables because on some systems
    15     pthread_mutex_lock and pthread_mutex_unlock must be called by the
    16     same thread.  That is never true of semaphores.  */
    17  
    18  struct go_sem
    19  {
    20    sem_t sem;
    21  
    22  #ifndef HAVE_SEM_TIMEDWAIT
    23    int timedwait;
    24    pthread_mutex_t mutex;
    25    pthread_cond_t cond;
    26  #endif
    27  };
    28  
    29  /* Create a semaphore.  */
    30  
    31  uintptr
    32  runtime_semacreate(void)
    33  {
    34    struct go_sem *p;
    35  
    36    /* Call malloc rather than runtime_malloc.  This will allocate space
    37       on the C heap.  We can't call runtime_malloc here because it
    38       could cause a deadlock.  */
    39    p = malloc (sizeof (struct go_sem));
    40    if (sem_init (&p->sem, 0, 0) != 0)
    41      runtime_throw ("sem_init");
    42  
    43  #ifndef HAVE_SEM_TIMEDWAIT
    44    if (pthread_mutex_init (&p->mutex, NULL) != 0)
    45      runtime_throw ("pthread_mutex_init");
    46    if (pthread_cond_init (&p->cond, NULL) != 0)
    47      runtime_throw ("pthread_cond_init");
    48  #endif
    49  
    50    return (uintptr) p;
    51  }
    52  
    53  /* Acquire m->waitsema.  */
    54  
    55  int32
    56  runtime_semasleep (int64 ns)
    57  {
    58    M *m;
    59    struct go_sem *sem;
    60    int r;
    61  
    62    m = runtime_m ();
    63    sem = (struct go_sem *) m->waitsema;
    64    if (ns >= 0)
    65      {
    66        int64 abs;
    67        struct timespec ts;
    68        int err;
    69  
    70        abs = ns + runtime_nanotime ();
    71        ts.tv_sec = abs / 1000000000LL;
    72        ts.tv_nsec = abs % 1000000000LL;
    73  
    74        err = 0;
    75  
    76  #ifdef HAVE_SEM_TIMEDWAIT
    77        r = sem_timedwait (&sem->sem, &ts);
    78        if (r != 0)
    79  	err = errno;
    80  #else
    81        if (pthread_mutex_lock (&sem->mutex) != 0)
    82  	runtime_throw ("pthread_mutex_lock");
    83  
    84        while ((r = sem_trywait (&sem->sem)) != 0)
    85  	{
    86  	  r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
    87  	  if (r != 0)
    88  	    {
    89  	      err = r;
    90  	      break;
    91  	    }
    92  	}
    93  
    94        if (pthread_mutex_unlock (&sem->mutex) != 0)
    95  	runtime_throw ("pthread_mutex_unlock");
    96  #endif
    97  
    98        if (err != 0)
    99  	{
   100  	  if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
   101  	    return -1;
   102  	  runtime_throw ("sema_timedwait");
   103  	}
   104        return 0;
   105      }
   106  
   107    while (sem_wait (&sem->sem) != 0)
   108      {
   109        if (errno == EINTR)
   110  	continue;
   111        runtime_throw ("sem_wait");
   112      }
   113  
   114    return 0;
   115  }
   116  
   117  /* Wake up mp->waitsema.  */
   118  
   119  void
   120  runtime_semawakeup (M *mp)
   121  {
   122    struct go_sem *sem;
   123  
   124    sem = (struct go_sem *) mp->waitsema;
   125    if (sem_post (&sem->sem) != 0)
   126      runtime_throw ("sem_post");
   127  
   128  #ifndef HAVE_SEM_TIMEDWAIT
   129    if (pthread_mutex_lock (&sem->mutex) != 0)
   130      runtime_throw ("pthread_mutex_lock");
   131    if (pthread_cond_broadcast (&sem->cond) != 0)
   132      runtime_throw ("pthread_cond_broadcast");
   133    if (pthread_mutex_unlock (&sem->mutex) != 0)
   134      runtime_throw ("pthread_mutex_unlock");
   135  #endif
   136  }
   137  
   138  void
   139  runtime_osinit (void)
   140  {
   141    runtime_ncpu = getproccount();
   142  }
   143  
   144  void
   145  runtime_goenvs (void)
   146  {
   147    runtime_goenvs_unix ();
   148  }