Prex Home / Browse Source - Prex Version: 0.9.0

root/sys/sync/cond.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cond_init
  2. cond_deallocate
  3. cond_destroy
  4. cond_cleanup
  5. cond_wait
  6. cond_signal
  7. cond_broadcast
  8. cond_valid
  9. cond_copyin

   1 /*-
   2  * Copyright (c) 2005-2007, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * cond.c - condition variable object
  32  */
  33 
  34 #include <kernel.h>
  35 #include <sched.h>
  36 #include <event.h>
  37 #include <kmem.h>
  38 #include <task.h>
  39 #include <sync.h>
  40 
  41 /* forward declarations */
  42 static int      cond_valid(cond_t);
  43 static int      cond_copyin(cond_t *, cond_t *);
  44 
  45 /*
  46  * Create and initialize a condition variable (CV).
  47  *
  48  * If an initialized condition variable is reinitialized,
  49  * undefined behavior results.
  50  */
  51 int
  52 cond_init(cond_t *cp)
  53 {
  54         task_t self = curtask;
  55         cond_t c;
  56 
  57         if (self->nsyncs >= MAXSYNCS)
  58                 return EAGAIN;
  59 
  60         if ((c = kmem_alloc(sizeof(struct cond))) == NULL)
  61                 return ENOMEM;
  62 
  63         event_init(&c->event, "condvar");
  64         c->owner = self;
  65 
  66         if (copyout(&c, cp, sizeof(c))) {
  67                 kmem_free(c);
  68                 return EFAULT;
  69         }
  70         sched_lock();
  71         list_insert(&self->conds, &c->task_link);
  72         self->nsyncs++;
  73         sched_unlock();
  74         return 0;
  75 }
  76 
  77 static void
  78 cond_deallocate(cond_t c)
  79 {
  80 
  81         c->owner->nsyncs--;
  82         list_remove(&c->task_link);
  83         kmem_free(c);
  84 }
  85 
  86 /*
  87  * Tear down a condition variable.
  88  *
  89  * If there are any blocked thread waiting for the specified
  90  * CV, it returns EBUSY.
  91  */
  92 int
  93 cond_destroy(cond_t *cp)
  94 {
  95         cond_t c;
  96 
  97         sched_lock();
  98         if (cond_copyin(cp, &c)) {
  99                 sched_unlock();
 100                 return EINVAL;
 101         }
 102         if (event_waiting(&c->event)) {
 103                 sched_unlock();
 104                 return EBUSY;
 105         }
 106         cond_deallocate(c);
 107         sched_unlock();
 108         return 0;
 109 }
 110 
 111 /*
 112  * Clean up for task termination.
 113  */
 114 void
 115 cond_cleanup(task_t task)
 116 {
 117         cond_t c;
 118 
 119         while (!list_empty(&task->conds)) {
 120                 c = list_entry(list_first(&task->conds),
 121                                struct cond, task_link);
 122                 cond_deallocate(c);
 123         }
 124 }
 125 
 126 /*
 127  * Wait on a condition.
 128  *
 129  * If the thread receives any exception while waiting CV, this
 130  * routine returns immediately with EINTR in order to invoke
 131  * exception handler. However, an application assumes this call
 132  * does NOT return with an error. So, the stub routine in a
 133  * system call library must call cond_wait() again if it gets
 134  * EINTR as error.
 135  */
 136 int
 137 cond_wait(cond_t *cp, mutex_t *mp)
 138 {
 139         cond_t c;
 140         int error, rc;
 141 
 142         if (copyin(cp, &c, sizeof(cp)))
 143                 return EINVAL;
 144 
 145         sched_lock();
 146         if (c == COND_INITIALIZER) {
 147                 if ((error = cond_init(cp)) != 0) {
 148                         sched_unlock();
 149                         return error;
 150                 }
 151                 copyin(cp, &c, sizeof(cp));
 152         } else {
 153                 if (!cond_valid(c)) {
 154                         sched_unlock();
 155                         return EINVAL;
 156                 }
 157         }
 158         /* unlock mutex */
 159         if ((error = mutex_unlock(mp)) != 0) {
 160                 sched_unlock();
 161                 return error;
 162         }
 163 
 164         /* and block */
 165         rc = sched_sleep(&c->event);
 166         if (rc == SLP_INTR)
 167                 error = EINTR;
 168         sched_unlock();
 169 
 170         /* grab mutex before returning */
 171         if (error == 0)
 172                 error = mutex_lock(mp);
 173 
 174         return error;
 175 }
 176 
 177 /*
 178  * Unblock one thread that is blocked on the specified CV.
 179  * The thread which has highest priority will be unblocked.
 180  */
 181 int
 182 cond_signal(cond_t *cp)
 183 {
 184         cond_t c;
 185 
 186         sched_lock();
 187         if (cond_copyin(cp, &c)) {
 188                 sched_unlock();
 189                 return EINVAL;
 190         }
 191         sched_wakeone(&c->event);
 192         sched_unlock();
 193         return 0;
 194 }
 195 
 196 /*
 197  * Unblock all threads that are blocked on the specified CV.
 198  */
 199 int
 200 cond_broadcast(cond_t *cp)
 201 {
 202         cond_t c;
 203 
 204         sched_lock();
 205         if (cond_copyin(cp, &c)) {
 206                 sched_unlock();
 207                 return EINVAL;
 208         }
 209         sched_wakeup(&c->event);
 210         sched_unlock();
 211         return 0;
 212 }
 213 
 214 /*
 215  * Check if the specified cv is valid.
 216  */
 217 static int
 218 cond_valid(cond_t c)
 219 {
 220         cond_t tmp;
 221         list_t head, n;
 222 
 223         head = &curtask->conds;
 224         for (n = list_first(head); n != head; n = list_next(n)) {
 225                 tmp = list_entry(n, struct cond, task_link);
 226                 if (tmp == c)
 227                         return 1;
 228         }
 229         return 0;
 230 }
 231 
 232 /*
 233  * cond_copyin - copy a condition variable from user space.
 234  * It also checks if the passed CV is valid.
 235  */
 236 static int
 237 cond_copyin(cond_t *ucp, cond_t *kcp)
 238 {
 239         cond_t c;
 240 
 241         if (copyin(ucp, &c, sizeof(ucp)) || !cond_valid(c))
 242                 return EINVAL;
 243         *kcp = c;
 244         return 0;
 245 }

/* [<][>][^][v][top][bottom][index][help] */