|
|
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.