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

Annotation of prex/sys/sync/sem.c, Revision 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,
        !            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.
        !            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:  *
        !            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.
        !            56:  */
        !            57: int
        !            58: sem_init(sem_t *sem, u_int value)
        !            59: {
        !            60:        struct sem *s;
        !            61:        int err = 0;
        !            62:
        !            63:        if (value > MAXSEMVAL)
        !            64:                return EINVAL;
        !            65:        if (umem_copyin(sem, &s, sizeof(sem_t)))
        !            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
        !            71:         * whether the semaphore is already allocated.
        !            72:         */
        !            73:        sched_lock();
        !            74:        if (sem_valid(s)) {
        !            75:                /*
        !            76:                 * Semaphore already exists.
        !            77:                 */
        !            78:                if (s->task != cur_task() &&
        !            79:                    !task_capable(CAP_SEMAPHORE))
        !            80:                        err = EPERM;
        !            81:                else if (event_waiting(&s->event))
        !            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:  *
        !           109:  * It also checks whether the passed semaphore is valid.
        !           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:        }
        !           146:        if (event_waiting(&s->event) || s->value == 0) {
        !           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.
        !           158:  *
        !           159:  * The value of timeout is msec unit. 0 for no timeout.
        !           160:  *
        !           161:  * sem_wait() locks the semaphore referred by sem only if the
        !           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.
        !           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:
        !           182:        while (s->value == 0) {
        !           183:                rc = sched_tsleep(&s->event, timeout);
        !           184:                if (rc == SLP_TIMEOUT) {
        !           185:                        err = ETIMEDOUT;
        !           186:                        goto out;
        !           187:                }
        !           188:                if (rc == SLP_INTR) {
        !           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:  *
        !           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.
        !           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