|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: * ! 25: */ ! 26: /* ! 27: * File: kern/sync_sema.c ! 28: * Author: Joseph CaraDonna ! 29: * ! 30: * Contains RT distributed semaphore synchronization services. ! 31: */ ! 32: /* ! 33: * Semaphores: Rule of Thumb ! 34: * ! 35: * A non-negative semaphore count means that the blocked threads queue is ! 36: * empty. A semaphore count of negative n means that the blocked threads ! 37: * queue contains n blocked threads. ! 38: */ ! 39: ! 40: #include <kern/misc_protos.h> ! 41: #include <kern/sync_sema.h> ! 42: #include <kern/spl.h> ! 43: #include <kern/ipc_kobject.h> ! 44: #include <kern/ipc_sync.h> ! 45: #include <kern/thread.h> ! 46: #include <kern/clock.h> ! 47: #include <ipc/ipc_port.h> ! 48: #include <ipc/ipc_space.h> ! 49: #include <kern/host.h> ! 50: #include <kern/wait_queue.h> ! 51: ! 52: unsigned int semaphore_event; ! 53: #define SEMAPHORE_EVENT ((event_t)&semaphore_event) ! 54: ! 55: /* ! 56: * forward declaration ! 57: */ ! 58: void semaphore_dereference( ! 59: semaphore_t semaphore); ! 60: ! 61: /* ! 62: * Routine: semaphore_create ! 63: * ! 64: * Creates a semaphore. ! 65: * The port representing the semaphore is returned as a parameter. ! 66: */ ! 67: kern_return_t ! 68: semaphore_create( ! 69: task_t task, ! 70: semaphore_t *new_semaphore, ! 71: int policy, ! 72: int value) ! 73: { ! 74: semaphore_t s = SEMAPHORE_NULL; ! 75: ! 76: *new_semaphore = SEMAPHORE_NULL; ! 77: ! 78: ! 79: if (task == TASK_NULL || value < 0 || policy > SYNC_POLICY_MAX) ! 80: return KERN_INVALID_ARGUMENT; ! 81: ! 82: s = (semaphore_t) kalloc (sizeof(struct semaphore)); ! 83: ! 84: if (s == SEMAPHORE_NULL) ! 85: return KERN_RESOURCE_SHORTAGE; ! 86: ! 87: wait_queue_init(&s->wait_queue, policy); /* also inits lock */ ! 88: s->count = value; ! 89: s->ref_count = 1; ! 90: ! 91: /* ! 92: * Create and initialize the semaphore port ! 93: */ ! 94: s->port = ipc_port_alloc_kernel(); ! 95: if (s->port == IP_NULL) { ! 96: /* This will deallocate the semaphore */ ! 97: semaphore_dereference(s); ! 98: return KERN_RESOURCE_SHORTAGE; ! 99: } ! 100: ! 101: ipc_kobject_set (s->port, (ipc_kobject_t) s, IKOT_SEMAPHORE); ! 102: ! 103: /* ! 104: * Associate the new semaphore with the task by adding ! 105: * the new semaphore to the task's semaphore list. ! 106: * ! 107: * Associate the task with the new semaphore by having the ! 108: * semaphores task pointer point to the owning task's structure. ! 109: */ ! 110: task_lock(task); ! 111: enqueue_head(&task->semaphore_list, (queue_entry_t) s); ! 112: task->semaphores_owned++; ! 113: task_unlock(task); ! 114: s->owner = task; ! 115: ! 116: /* ! 117: * Activate semaphore ! 118: */ ! 119: s->active = TRUE; ! 120: *new_semaphore = s; ! 121: ! 122: return KERN_SUCCESS; ! 123: } ! 124: ! 125: /* ! 126: * Routine: semaphore_destroy ! 127: * ! 128: * Destroys a semaphore. This call will only succeed if the ! 129: * specified task is the SAME task name specified at the semaphore's ! 130: * creation. ! 131: * ! 132: * All threads currently blocked on the semaphore are awoken. These ! 133: * threads will return with the KERN_TERMINATED error. ! 134: */ ! 135: kern_return_t ! 136: semaphore_destroy( ! 137: task_t task, ! 138: semaphore_t semaphore) ! 139: { ! 140: int old_count; ! 141: thread_t thread; ! 142: spl_t spl_level; ! 143: ! 144: ! 145: if (task == TASK_NULL || semaphore == SEMAPHORE_NULL) ! 146: return KERN_INVALID_ARGUMENT; ! 147: ! 148: if (semaphore->owner != task) ! 149: return KERN_INVALID_RIGHT; ! 150: ! 151: ! 152: spl_level = splsched(); ! 153: wait_queue_lock(&semaphore->wait_queue); ! 154: ! 155: if (!semaphore->active) { ! 156: wait_queue_unlock(&semaphore->wait_queue); ! 157: splx(spl_level); ! 158: return KERN_TERMINATED; ! 159: } ! 160: ! 161: /* ! 162: * Deactivate semaphore ! 163: */ ! 164: semaphore->active = FALSE; ! 165: ! 166: /* ! 167: * Wakeup blocked threads ! 168: */ ! 169: old_count = semaphore->count; ! 170: semaphore->count = 0; ! 171: ! 172: if (old_count < 0) { ! 173: wait_queue_wakeup_all_locked(&semaphore->wait_queue, ! 174: SEMAPHORE_EVENT, ! 175: THREAD_RESTART, ! 176: TRUE); /* unlock? */ ! 177: } else { ! 178: wait_queue_unlock(&semaphore->wait_queue); ! 179: } ! 180: ! 181: /* ! 182: * Disown semaphore ! 183: */ ! 184: task_lock(task); ! 185: remqueue(&task->semaphore_list, (queue_entry_t) semaphore); ! 186: task->semaphores_owned--; ! 187: task_unlock(task); ! 188: ! 189: splx(spl_level); ! 190: ! 191: /* ! 192: * Deallocate ! 193: * ! 194: * Drop the semaphore reference, which inturn deallocates the ! 195: * semaphore structure if the reference count goes to zero. ! 196: */ ! 197: ipc_port_dealloc_kernel(semaphore->port); ! 198: semaphore_dereference(semaphore); ! 199: ! 200: return KERN_SUCCESS; ! 201: } ! 202: ! 203: /* ! 204: * Routine: semaphore_signal_thread ! 205: * ! 206: * If the specified thread_act is blocked on the semaphore, it is ! 207: * woken up. Otherwise the caller gets KERN_NOT_WAITING and the ! 208: * semaphore is unchanged. ! 209: */ ! 210: kern_return_t ! 211: semaphore_signal_thread( ! 212: semaphore_t semaphore, ! 213: thread_act_t thread_act) ! 214: { ! 215: kern_return_t ret = KERN_NOT_WAITING; ! 216: spl_t spl_level; ! 217: ! 218: if (semaphore == SEMAPHORE_NULL) ! 219: return KERN_INVALID_ARGUMENT; ! 220: ! 221: spl_level = splsched(); ! 222: wait_queue_lock(&semaphore->wait_queue); ! 223: ! 224: if (!semaphore->active) { ! 225: wait_queue_unlock(&semaphore->wait_queue); ! 226: splx(spl_level); ! 227: return KERN_TERMINATED; ! 228: } ! 229: if (semaphore->count < 0) { ! 230: ret = wait_queue_wakeup_thread_locked(&semaphore->wait_queue, ! 231: SEMAPHORE_EVENT, ! 232: thread_act->thread, ! 233: THREAD_AWAKENED, ! 234: TRUE); /* unlock? */ ! 235: } else { ! 236: wait_queue_unlock(&semaphore->wait_queue); ! 237: } ! 238: splx(spl_level); ! 239: ! 240: return(ret); ! 241: } ! 242: ! 243: /* ! 244: * Routine: semaphore_signal ! 245: * ! 246: * Increments the semaphore count by one. If any threads are blocked ! 247: * on the semaphore ONE is woken up. ! 248: */ ! 249: kern_return_t ! 250: semaphore_signal( ! 251: semaphore_t semaphore) ! 252: { ! 253: spl_t spl_level; ! 254: ! 255: if (semaphore == SEMAPHORE_NULL) ! 256: return KERN_INVALID_ARGUMENT; ! 257: ! 258: spl_level = splsched(); ! 259: wait_queue_lock(&semaphore->wait_queue); ! 260: ! 261: if (!semaphore->active) { ! 262: wait_queue_unlock(&semaphore->wait_queue); ! 263: splx(spl_level); ! 264: return KERN_TERMINATED; ! 265: } ! 266: if (semaphore->count < 0) { ! 267: if (wait_queue_wakeup_one_locked(&semaphore->wait_queue, ! 268: SEMAPHORE_EVENT, ! 269: THREAD_AWAKENED, ! 270: FALSE) == KERN_NOT_WAITING) { ! 271: ! 272: semaphore->count = 1; /* waiters have busted out */ ! 273: /* becomes a pre-signal. */ ! 274: } ! 275: } else { ! 276: semaphore->count++; ! 277: } ! 278: wait_queue_unlock(&semaphore->wait_queue); ! 279: splx(spl_level); ! 280: ! 281: return KERN_SUCCESS; ! 282: } ! 283: ! 284: /* ! 285: * Routine: semaphore_signal_all ! 286: * ! 287: * Awakens ALL threads currently blocked on the semaphore. ! 288: * The semaphore count returns to zero. ! 289: */ ! 290: kern_return_t ! 291: semaphore_signal_all( ! 292: semaphore_t semaphore) ! 293: { ! 294: int old_count; ! 295: spl_t spl_level; ! 296: ! 297: if (semaphore == SEMAPHORE_NULL) ! 298: return KERN_INVALID_ARGUMENT; ! 299: ! 300: spl_level = splsched(); ! 301: wait_queue_lock(&semaphore->wait_queue); ! 302: ! 303: if (!semaphore->active) { ! 304: wait_queue_unlock(&semaphore->wait_queue); ! 305: splx(spl_level); ! 306: return KERN_TERMINATED; ! 307: } ! 308: ! 309: old_count = semaphore->count; ! 310: semaphore->count = 0; /* always reset */ ! 311: ! 312: if (old_count < 0) { ! 313: wait_queue_wakeup_all_locked(&semaphore->wait_queue, ! 314: SEMAPHORE_EVENT, ! 315: THREAD_AWAKENED, ! 316: TRUE); /* unlock? */ ! 317: } else { ! 318: wait_queue_unlock(&semaphore->wait_queue); ! 319: } ! 320: splx(spl_level); ! 321: ! 322: return KERN_SUCCESS; ! 323: } ! 324: ! 325: ! 326: /* ! 327: * Routine: semaphore_wait_common ! 328: * ! 329: * Wait on a semaphore. If the semaphore has been pre-posted, it just ! 330: * claims one count, and returns success. Otherwise, set up to block. ! 331: */ ! 332: kern_return_t ! 333: semaphore_wait_common( ! 334: semaphore_t semaphore, ! 335: mach_timespec_t *wait_time) ! 336: { ! 337: AbsoluteTime abstime, nsinterval; ! 338: int wait_result; ! 339: spl_t spl_level; ! 340: ! 341: if (semaphore == SEMAPHORE_NULL) ! 342: return KERN_INVALID_ARGUMENT; ! 343: ! 344: if (wait_time != 0) { ! 345: if (BAD_MACH_TIMESPEC(wait_time)) ! 346: return KERN_INVALID_VALUE; ! 347: ! 348: clock_interval_to_absolutetime_interval( ! 349: wait_time->tv_sec, NSEC_PER_SEC, &abstime); ! 350: clock_interval_to_absolutetime_interval( ! 351: wait_time->tv_nsec, 1, &nsinterval); ! 352: ADD_ABSOLUTETIME(&abstime, &nsinterval); ! 353: clock_absolutetime_interval_to_deadline(abstime, &abstime); ! 354: } ! 355: ! 356: restart: ! 357: spl_level = splsched(); ! 358: wait_queue_lock(&semaphore->wait_queue); ! 359: ! 360: if (!semaphore->active) { ! 361: wait_queue_unlock(&semaphore->wait_queue); ! 362: splx(spl_level); ! 363: return KERN_TERMINATED; ! 364: } ! 365: ! 366: if (semaphore->count > 0) { ! 367: semaphore->count--; ! 368: wait_queue_unlock(&semaphore->wait_queue); ! 369: splx(spl_level); ! 370: return KERN_SUCCESS; ! 371: } ! 372: ! 373: if (wait_time != 0 && wait_time->tv_sec == 0 && wait_time->tv_nsec == 0) { ! 374: wait_queue_unlock(&semaphore->wait_queue); ! 375: splx(spl_level); ! 376: return KERN_OPERATION_TIMED_OUT; ! 377: } ! 378: ! 379: semaphore->count = -1; /* we don't keep an actual count */ ! 380: ! 381: wait_queue_assert_wait_locked(&semaphore->wait_queue, ! 382: SEMAPHORE_EVENT, ! 383: THREAD_ABORTSAFE, ! 384: TRUE); /* unlock? */ ! 385: /* semaphore->wait_queue is unlocked */ ! 386: ! 387: splx(spl_level); ! 388: ! 389: if (wait_time != 0) ! 390: thread_set_timer_deadline(abstime); ! 391: ! 392: wait_result = thread_block((void (*)(void))0); ! 393: ! 394: if (wait_time != 0) { ! 395: thread_cancel_timer(); ! 396: } ! 397: ! 398: switch (wait_result) { ! 399: case THREAD_AWAKENED: ! 400: return KERN_SUCCESS; ! 401: ! 402: case THREAD_TIMED_OUT: ! 403: return KERN_OPERATION_TIMED_OUT; ! 404: ! 405: case THREAD_INTERRUPTED: ! 406: return KERN_ABORTED; ! 407: ! 408: case THREAD_RESTART: ! 409: goto restart; ! 410: ! 411: default: ! 412: panic("semaphore_wait_common\n"); ! 413: break; ! 414: } ! 415: } ! 416: ! 417: ! 418: /* ! 419: * Routine: semaphore_wait ! 420: * ! 421: * Decrements the semaphore count by one. If the count is negative ! 422: * after the decrement, the calling thread blocks. ! 423: * ! 424: * Assumes: Never called from interrupt context. ! 425: */ ! 426: kern_return_t ! 427: semaphore_wait( ! 428: semaphore_t semaphore) ! 429: { ! 430: return (semaphore_wait_common(semaphore, (mach_timespec_t *) 0)); ! 431: } ! 432: ! 433: /* ! 434: * Routine: semaphore_timedwait ! 435: * ! 436: * Decrements the semaphore count by one. If the count is negative ! 437: * after the decrement, the calling thread blocks. ! 438: * Sleep for max 'wait_time' (0=>forever) ! 439: * ! 440: * Assumes: Never called from interrupt context. ! 441: */ ! 442: kern_return_t ! 443: semaphore_timedwait( ! 444: semaphore_t semaphore, ! 445: mach_timespec_t wait_time) ! 446: { ! 447: return (semaphore_wait_common(semaphore, &wait_time)); ! 448: } ! 449: ! 450: /* ! 451: * Routine: semaphore_reference ! 452: * ! 453: * Take out a reference on a semaphore. This keeps the data structure ! 454: * in existence (but the semaphore may be deactivated). ! 455: */ ! 456: void ! 457: semaphore_reference( ! 458: semaphore_t semaphore) ! 459: { ! 460: spl_t spl_level; ! 461: ! 462: spl_level = splsched(); ! 463: wait_queue_lock(&semaphore->wait_queue); ! 464: ! 465: semaphore->ref_count++; ! 466: ! 467: wait_queue_unlock(&semaphore->wait_queue); ! 468: splx(spl_level); ! 469: } ! 470: ! 471: /* ! 472: * Routine: semaphore_dereference ! 473: * ! 474: * Release a reference on a semaphore. If this is the last reference, ! 475: * the semaphore data structure is deallocated. ! 476: */ ! 477: void ! 478: semaphore_dereference( ! 479: semaphore_t semaphore) ! 480: { ! 481: int ref_count; ! 482: spl_t spl_level; ! 483: ! 484: if (semaphore != NULL) { ! 485: spl_level = splsched(); ! 486: wait_queue_lock(&semaphore->wait_queue); ! 487: ! 488: ref_count = --(semaphore->ref_count); ! 489: ! 490: wait_queue_unlock(&semaphore->wait_queue); ! 491: splx(spl_level); ! 492: ! 493: if (ref_count == 0) { ! 494: assert(wait_queue_empty(&semaphore->wait_queue)); ! 495: kfree((vm_offset_t) semaphore, sizeof(struct semaphore)); ! 496: } ! 497: } ! 498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.