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