[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     ! 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