Annotation of prex-old/sys/sync/sem.c, Revision 1.1.1.1
1.1 nbrk 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: /*
35: * All of the Prex semaphore is un-named semaphore. Instead, the
36: * named semaphore is implemented by a file system server.
37: * In order to access the other task's semaphore, the task must
38: * have CAP_SEMAPHORE capability.
39: */
40:
41: #include <kernel.h>
42: #include <event.h>
43: #include <sched.h>
44: #include <kmem.h>
45: #include <thread.h>
46: #include <sync.h>
47:
48: /*
49: * sem_init - initialize a semaphore.
50: * @sem: ID for new semaphore.
51: * @value: initial semaphore count.
52: *
53: * sem_init() creates a new semaphore if the specified semaphore does
54: * not exist yet. If the semaphore already exists, it is re-initialized
55: * only if nobody is waiting for it. The initial semaphore value is set
56: * to the requested value.
57: */
58: int
59: sem_init(sem_t *sem, u_int value)
60: {
61: struct sem *s, *sem_org;
62: int err = 0;
63:
64: if (value > MAXSEMVAL)
65: return EINVAL;
66: if (umem_copyin(sem, &sem_org, sizeof(sem_t)))
67: return EFAULT;
68:
69: /*
70: * An application can call sem_init() to reset the
71: * value of existing semaphore. So, we have to check
72: * the semaphore is already allocated.
73: */
74: sched_lock();
75: if (sem_valid(sem_org)) {
76: /*
77: * Semaphore already exists.
78: */
79: if (sem_org->task != cur_task() &&
80: !task_capable(CAP_SEMAPHORE))
81: err = EPERM;
82: else if (event_waiting(&sem_org->event))
83: err = EBUSY;
84: else
85: s->value = value;
86: } else {
87: /*
88: * Create new semaphore.
89: */
90: if ((s = kmem_alloc(sizeof(struct sem))) == NULL)
91: err = ENOSPC;
92: else {
93: event_init(&s->event, "semaphore");
94: s->task = cur_task();
95: s->value = value;
96: s->magic = SEM_MAGIC;
97: if (umem_copyout(&s, sem, sizeof(sem_t))) {
98: kmem_free(s);
99: err = EFAULT;
100: }
101: }
102: }
103: sched_unlock();
104: return err;
105: }
106:
107: /*
108: * sem_copyin - copy a semaphore from user space.
109: * @usem: pointer to semaphore in user space.
110: * @ksem: pointer to semaphore in kernel space.
111: *
112: * It also checks if the passed semaphore is valid.
113: */
114: static int
115: sem_copyin(sem_t *usem, sem_t *ksem)
116: {
117: sem_t s;
118:
119: if (umem_copyin(usem, &s, sizeof(sem_t)))
120: return EFAULT;
121: if (!sem_valid(s))
122: return EINVAL;
123: /*
124: * Need a capability to access semaphores created
125: * by another task.
126: */
127: if (s->task != cur_task() && !task_capable(CAP_SEMAPHORE))
128: return EPERM;
129: *ksem = s;
130: return 0;
131: }
132:
133: /*
134: * Destroy a semaphore.
135: * If some thread is waiting for the specified semaphore,
136: * this routine fails with EBUSY.
137: */
138: int
139: sem_destroy(sem_t *sem)
140: {
141: sem_t s;
142: int err;
143:
144: sched_lock();
145: if ((err = sem_copyin(sem, &s))) {
146: sched_unlock();
147: return err;
148: }
149: if (event_waiting(&s->event) || s->value <= 0) {
150: sched_unlock();
151: return EBUSY;
152: }
153: s->magic = 0;
154: kmem_free(s);
155: sched_unlock();
156: return 0;
157: }
158:
159: /*
160: * sem_wait - lock a semaphore.
161: * @sem: semaphore ID
162: * @timeout: time out value in msec. 0 for no timeout.
163: *
164: * sem_wait() locks the semaphore referred by sem only if the
165: * semaphore value is currently positive. The thread will sleep
166: * while the semaphore value is zero. It decrements the semaphore
167: * value in return.
168: *
169: * If waiting thread receives any exception, this routine returns
170: * with EINTR in order to invoke exception handler. But, an
171: * application assumes this call does NOT return with error. So,
172: * system call stub routine must re-call automatically if it gets
173: * EINTR.
174: */
175: int
176: sem_wait(sem_t *sem, u_long timeout)
177: {
178: sem_t s;
179: int err, rc;
180:
181: sched_lock();
182: if ((err = sem_copyin(sem, &s)))
183: goto out;
184:
185: while (s->value <= 0) {
186: rc = sched_tsleep(&s->event, timeout);
187: if (rc == SLP_TIMEOUT) {
188: err = ETIMEDOUT;
189: goto out;
190: } else if (rc == SLP_INTR) {
191: err = EINTR;
192: goto out;
193: }
194: /* Kick scheduler */
195: sched_unlock();
196: sched_lock();
197: }
198: s->value--;
199: out:
200: sched_unlock();
201: return err;
202: }
203:
204: /*
205: * Try to lock a semaphore.
206: * If the semaphore is already locked, it just returns EAGAIN.
207: */
208: int
209: sem_trywait(sem_t *sem)
210: {
211: sem_t s;
212: int err;
213:
214: sched_lock();
215: if ((err = sem_copyin(sem, &s))) {
216: sched_unlock();
217: return err;
218: }
219: if (s->value > 0)
220: s->value--;
221: else
222: err = EAGAIN;
223: sched_unlock();
224: return err;
225: }
226:
227: /*
228: * Unlock a semaphore.
229: *
230: * If the semaphore value becomes non zero, then one of the threads
231: * blocked waiting for the semaphore will be unblocked.
232: * This is non-blocking operation.
233: */
234: int
235: sem_post(sem_t *sem)
236: {
237: sem_t s;
238: int err;
239:
240: sched_lock();
241: if ((err = sem_copyin(sem, &s))) {
242: sched_unlock();
243: return err;
244: }
245: if (s->value >= MAXSEMVAL) {
246: sched_unlock();
247: return ERANGE;
248: }
249: s->value++;
250: if (s->value > 0)
251: sched_wakeone(&s->event);
252: sched_unlock();
253: return 0;
254: }
255:
256: /*
257: * Get the semaphore value.
258: */
259: int
260: sem_getvalue(sem_t *sem, u_int *value)
261: {
262: sem_t s;
263: int err;
264:
265: sched_lock();
266: if ((err = sem_copyin(sem, &s))) {
267: sched_unlock();
268: return err;
269: }
270: if (umem_copyout(&s->value, value, sizeof(int)))
271: err = EFAULT;
272: sched_unlock();
273: return err;
274: }
CVSweb