1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * condvar(9f)
  18  */
  19 
  20 /* This is the API we're emulating */
  21 #include <sys/condvar.h>
  22 
  23 #include <sys/errno.h>
  24 #include <sys/debug.h>
  25 #include <sys/thread.h>
  26 
  27 /* avoiding synch.h */
  28 int     _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
  29 int     _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
  30 int     _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
  31 int     _lwp_cond_signal(lwp_cond_t *);
  32 int     _lwp_cond_broadcast(lwp_cond_t *);
  33 
  34 
  35 extern clock_t ddi_get_lbolt(void);
  36 extern void clock2ts(clock_t, timespec_t *);
  37 
  38 static int cv__wait(kcondvar_t *, kmutex_t *, int);
  39 static clock_t cv__twait(kcondvar_t *, kmutex_t *, clock_t, int);
  40 
  41 static const lwp_cond_t  default_cv =
  42         {{{0, 0, 0, 0}, USYNC_THREAD, _COND_MAGIC}, 0};
  43 
  44 
  45 /* ARGSUSED */
  46 void
  47 cv_init(kcondvar_t *cv, char *name, kcv_type_t typ, void *arg)
  48 {
  49         *cv = default_cv;
  50 }
  51 
  52 /* ARGSUSED */
  53 void
  54 cv_destroy(kcondvar_t *cv)
  55 {
  56 }
  57 
  58 void
  59 cv_signal(kcondvar_t *cv)
  60 {
  61         (void) _lwp_cond_signal(cv);
  62 }
  63 
  64 void
  65 cv_broadcast(kcondvar_t *cv)
  66 {
  67         (void) _lwp_cond_broadcast(cv);
  68 }
  69 
  70 void
  71 cv_wait(kcondvar_t *cv, kmutex_t *mp)
  72 {
  73         (void) cv__wait(cv, mp, 0);
  74 }
  75 
  76 int
  77 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
  78 {
  79         return (cv__wait(cv, mp, 1));
  80 }
  81 
  82 int
  83 cv__wait(kcondvar_t *cv, kmutex_t *mp, int sigok)
  84 {
  85         int err;
  86 
  87 top:
  88         ASSERT(mp->m_owner == _curthread());
  89         mp->m_owner = _KTHREAD_INVALID;
  90         err = _lwp_cond_wait(cv, &mp->m_lock);
  91         mp->m_owner = _curthread();
  92 
  93         if (err == 0)
  94                 return (1);
  95         if (err == EINTR) {
  96                 if (sigok)
  97                         return (0);
  98                 goto top;
  99         }
 100         return (-1);
 101 }
 102 
 103 clock_t
 104 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
 105 {
 106         clock_t delta;
 107 
 108         delta = abstime - ddi_get_lbolt();
 109         return (cv__twait(cv, mp, delta, 0));
 110 }
 111 
 112 clock_t
 113 cv_timedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
 114 {
 115         clock_t delta;
 116 
 117         delta = abstime - ddi_get_lbolt();
 118         return (cv__twait(cv, mp, delta, 1));
 119 }
 120 
 121 clock_t
 122 cv_reltimedwait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, time_res_t res)
 123 {
 124         _NOTE(ARGUNUSED(res))
 125 
 126         return (cv__twait(cv, mp, delta, 0));
 127 }
 128 
 129 clock_t
 130 cv_reltimedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t delta,
 131     time_res_t res)
 132 {
 133         _NOTE(ARGUNUSED(res))
 134 
 135         return (cv__twait(cv, mp, delta, 1));
 136 }
 137 
 138 /*
 139  * Factored out implementation of all the cv_*timedwait* functions.
 140  * Note that the delta passed in is relative to the (simulated)
 141  * current time reported by ddi_get_lbolt().  Convert that to
 142  * timespec format and keep calling _lwp_cond_reltimedwait,
 143  * which (NB!) decrements that delta in-place!
 144  */
 145 static clock_t
 146 cv__twait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, int sigok)
 147 {
 148         timestruc_t ts;
 149         int err;
 150 
 151         if (delta <= 0)
 152                 return (-1);
 153 
 154         clock2ts(delta, &ts);
 155 
 156 top:
 157         if (ts.tv_sec == 0 && ts.tv_nsec == 0)
 158                 return (-1);
 159 
 160         ASSERT(mp->m_owner == _curthread());
 161         mp->m_owner = _KTHREAD_INVALID;
 162         err = _lwp_cond_reltimedwait(cv, &mp->m_lock, &ts);
 163         mp->m_owner = _curthread();
 164 
 165         switch (err) {
 166         case 0:
 167                 return (1);
 168         case EINTR:
 169                 if (sigok)
 170                         return (0);
 171                 goto top;
 172         default:
 173                 ASSERT(0);
 174                 /* FALLTHROUGH */
 175         case ETIME:
 176                 break;
 177         }
 178 
 179         return (-1);
 180 }