|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/sys/sync/sem.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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 * sem.c - semaphore support 32 */ 33 34 #include <kernel.h> 35 #include <event.h> 36 #include <sched.h> 37 #include <kmem.h> 38 #include <task.h> 39 #include <sync.h> 40 41 /* forward declarations */ 42 static int sem_valid(sem_t); 43 static void sem_release(sem_t); 44 static void sem_reference(sem_t); 45 static int sem_copyin(sem_t *, sem_t *); 46 47 static struct sem *sem_list = NULL; /* list head of semaphore list */ 48 49 /* 50 * sem_init - initialize a semaphore; required before use. 51 * 52 * sem_init() creates a new semaphore if the specified 53 * semaphore does not exist yet. If the semaphore already 54 * exists, it is re-initialized only if nobody is waiting for 55 * it. The initial semaphore value is set to the requested 56 * value. A semaphore can be shared among different tasks. 57 */ 58 int 59 sem_init(sem_t *sp, u_int value) 60 { 61 task_t self = curtask; 62 sem_t s; 63 64 /* 65 * A couple of quick sanity checks. 66 */ 67 if (self->nsyncs >= MAXSYNCS) 68 return EAGAIN; 69 if (value > MAXSEMVAL) 70 return EINVAL; 71 if (copyin(sp, &s, sizeof(sp))) 72 return EFAULT; 73 74 /* 75 * An application can call sem_init() to reset the 76 * value of existing semaphore. So, we have to check 77 * whether the semaphore is already allocated. 78 */ 79 sched_lock(); 80 if (sem_valid(s)) { 81 /* 82 * Semaphore already exists. 83 */ 84 if (s->owner != self) { 85 sched_unlock(); 86 return EINVAL; 87 } 88 if (event_waiting(&s->event)) { 89 sched_unlock(); 90 return EBUSY; 91 } 92 s->value = value; 93 94 } else { 95 /* 96 * Create new semaphore. 97 */ 98 if ((s = kmem_alloc(sizeof(struct sem))) == NULL) { 99 sched_unlock(); 100 return ENOSPC; 101 } 102 if (copyout(&s, sp, sizeof(s))) { 103 kmem_free(s); 104 sched_unlock(); 105 return EFAULT; 106 } 107 event_init(&s->event, "semaphore"); 108 s->owner = self; 109 s->refcnt = 1; 110 s->value = value; 111 112 list_insert(&self->sems, &s->task_link); 113 self->nsyncs++; 114 s->next = sem_list; 115 sem_list = s; 116 } 117 sched_unlock(); 118 return 0; 119 } 120 121 /* 122 * Destroy a semaphore. 123 * If some thread is waiting for the specified semaphore, 124 * this routine fails with EBUSY. 125 */ 126 int 127 sem_destroy(sem_t *sp) 128 { 129 sem_t s; 130 131 sched_lock(); 132 if (sem_copyin(sp, &s) || s->owner != curtask) { 133 sched_unlock(); 134 return EINVAL; 135 } 136 if (event_waiting(&s->event) || s->value == 0) { 137 sched_unlock(); 138 return EBUSY; 139 } 140 sem_release(s); 141 sched_unlock(); 142 return 0; 143 } 144 145 /* 146 * sem_wait - lock a semaphore. 147 * 148 * The value of timeout is msec unit. 0 for no timeout. 149 * 150 * sem_wait() locks the semaphore referred by sem only if the 151 * semaphore value is currently positive. The thread will 152 * sleep while the semaphore value is zero. It decrements the 153 * semaphore value in return. 154 * 155 * If waiting thread receives any exception, this routine 156 * returns with EINTR in order to invoke exception 157 * handler. But, an application assumes this call does NOT 158 * return with an error. So, the system call stub routine will 159 * automatically call sem_wait again if it gets EINTR. 160 */ 161 int 162 sem_wait(sem_t *sp, u_long timeout) 163 { 164 sem_t s; 165 int rc, error = 0; 166 167 sched_lock(); 168 if (sem_copyin(sp, &s)) { 169 sched_unlock(); 170 return EINVAL; 171 } 172 sem_reference(s); 173 174 while (s->value == 0) { 175 rc = sched_tsleep(&s->event, timeout); 176 if (rc == SLP_TIMEOUT) { 177 error = ETIMEDOUT; 178 break; 179 } 180 if (rc == SLP_INTR) { 181 error = EINTR; 182 break; 183 } 184 /* 185 * We have to check the semaphore value again 186 * because another thread may run and acquire 187 * the semaphore before us. 188 */ 189 } 190 if (!error) 191 s->value--; 192 193 sem_release(s); 194 sched_unlock(); 195 return error; 196 } 197 198 /* 199 * Try to lock a semaphore. 200 * If the semaphore is already locked, it just returns EAGAIN. 201 */ 202 int 203 sem_trywait(sem_t *sp) 204 { 205 sem_t s; 206 207 sched_lock(); 208 if (sem_copyin(sp, &s)) { 209 sched_unlock(); 210 return EINVAL; 211 } 212 if (s->value == 0) { 213 sched_unlock(); 214 return EAGAIN; 215 } 216 s->value--; 217 sched_unlock(); 218 return 0; 219 } 220 221 /* 222 * Unlock a semaphore. 223 * 224 * If the semaphore value becomes non zero, then one of 225 * the threads blocked waiting for the semaphore will be 226 * unblocked. This is non-blocking operation. 227 */ 228 int 229 sem_post(sem_t *sp) 230 { 231 sem_t s; 232 233 sched_lock(); 234 if (sem_copyin(sp, &s)) { 235 sched_unlock(); 236 return EINVAL; 237 } 238 if (s->value >= MAXSEMVAL) { 239 sched_unlock(); 240 return ERANGE; 241 } 242 s->value++; 243 if (s->value > 0) 244 sched_wakeone(&s->event); 245 246 sched_unlock(); 247 return 0; 248 } 249 250 /* 251 * Get the semaphore value. 252 */ 253 int 254 sem_getvalue(sem_t *sp, u_int *value) 255 { 256 sem_t s; 257 258 sched_lock(); 259 if (sem_copyin(sp, &s)) { 260 sched_unlock(); 261 return EINVAL; 262 } 263 if (copyout(&s->value, value, sizeof(s->value))) { 264 sched_unlock(); 265 return EFAULT; 266 } 267 sched_unlock(); 268 return 0; 269 } 270 271 /* 272 * Take out a reference on a semaphore. 273 */ 274 static void 275 sem_reference(sem_t s) 276 { 277 278 s->refcnt++; 279 } 280 281 /* 282 * Release a reference on a semaphore. If this is the last 283 * reference, the semaphore data structure is deallocated. 284 */ 285 static void 286 sem_release(sem_t s) 287 { 288 sem_t *sp; 289 290 if (--s->refcnt > 0) 291 return; 292 293 list_remove(&s->task_link); 294 s->owner->nsyncs--; 295 296 for (sp = &sem_list; *sp; sp = &(*sp)->next) { 297 if (*sp == s) { 298 *sp = s->next; 299 break; 300 } 301 } 302 kmem_free(s); 303 } 304 305 void 306 sem_cleanup(task_t task) 307 { 308 list_t head, n; 309 sem_t s; 310 311 head = &task->sems; 312 for (n = list_first(head); n != head; n = list_next(n)) { 313 s = list_entry(n, struct sem, task_link); 314 sem_release(s); 315 } 316 } 317 318 static int 319 sem_valid(sem_t s) 320 { 321 sem_t tmp; 322 323 for (tmp = sem_list; tmp; tmp = tmp->next) { 324 if (tmp == s) 325 return 1; 326 } 327 return 0; 328 } 329 330 /* 331 * sem_copyin - copy a semaphore from user space. 332 * 333 * It also checks whether the passed semaphore is valid. 334 */ 335 static int 336 sem_copyin(sem_t *usp, sem_t *ksp) 337 { 338 sem_t s; 339 340 if (copyin(usp, &s, sizeof(usp)) || !sem_valid(s)) 341 return EINVAL; 342 343 *ksp = s; 344 return 0; 345 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |