[BACK]Return to sem.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / sync

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