Home | History | Annotate | Line # | Download | only in librt
sem.c revision 1.3.30.1
      1  1.3.30.1     yamt /*	$NetBSD: sem.c,v 1.3.30.1 2008/05/18 12:30:43 yamt Exp $	*/
      2       1.1  thorpej 
      3       1.1  thorpej /*-
      4       1.1  thorpej  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5       1.1  thorpej  * All rights reserved.
      6       1.1  thorpej  *
      7       1.1  thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  thorpej  * by Jason R. Thorpe.
      9       1.1  thorpej  *
     10       1.1  thorpej  * Redistribution and use in source and binary forms, with or without
     11       1.1  thorpej  * modification, are permitted provided that the following conditions
     12       1.1  thorpej  * are met:
     13       1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     14       1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     15       1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     18       1.1  thorpej  *
     19       1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  thorpej  */
     31       1.1  thorpej 
     32       1.1  thorpej /*
     33       1.1  thorpej  * Copyright (C) 2000 Jason Evans <jasone (at) freebsd.org>.
     34       1.1  thorpej  * All rights reserved.
     35       1.1  thorpej  *
     36       1.1  thorpej  * Redistribution and use in source and binary forms, with or without
     37       1.1  thorpej  * modification, are permitted provided that the following conditions
     38       1.1  thorpej  * are met:
     39       1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     40       1.1  thorpej  *    notice(s), this list of conditions and the following disclaimer as
     41       1.1  thorpej  *    the first lines of this file unmodified other than the possible
     42       1.1  thorpej  *    addition of one or more copyright notices.
     43       1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     44       1.1  thorpej  *    notice(s), this list of conditions and the following disclaimer in
     45       1.1  thorpej  *    the documentation and/or other materials provided with the
     46       1.1  thorpej  *    distribution.
     47       1.1  thorpej  *
     48       1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
     49       1.1  thorpej  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     50       1.1  thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     51       1.1  thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
     52       1.1  thorpej  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     53       1.1  thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     54       1.1  thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     55       1.1  thorpej  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     56       1.1  thorpej  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     57       1.1  thorpej  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     58       1.1  thorpej  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     59       1.1  thorpej  */
     60       1.2    lukem 
     61       1.2    lukem #include <sys/cdefs.h>
     62  1.3.30.1     yamt __RCSID("$NetBSD: sem.c,v 1.3.30.1 2008/05/18 12:30:43 yamt Exp $");
     63       1.1  thorpej 
     64       1.1  thorpej /*
     65       1.1  thorpej  * If an application is linked against both librt and libpthread, the
     66       1.1  thorpej  * libpthread versions must be used.  Provide weak aliases to cause
     67       1.1  thorpej  * this behavior.
     68       1.1  thorpej  */
     69       1.1  thorpej #define	sem_init	_librt_sem_init
     70       1.1  thorpej #define	sem_destroy	_librt_sem_destroy
     71       1.1  thorpej #define	sem_open	_librt_sem_open
     72       1.1  thorpej #define	sem_close	_librt_sem_close
     73       1.1  thorpej #define	sem_unlink	_librt_sem_unlink
     74       1.1  thorpej #define	sem_wait	_librt_sem_wait
     75       1.1  thorpej #define	sem_trywait	_librt_sem_trywait
     76       1.1  thorpej #define	sem_post	_librt_sem_post
     77       1.1  thorpej #define	sem_getvalue	_librt_sem_getvalue
     78       1.1  thorpej 
     79       1.1  thorpej #define	_LIBC		/* XXX to get semid_t type */
     80       1.1  thorpej 
     81       1.1  thorpej #include <sys/types.h>
     82       1.1  thorpej #include <sys/ksem.h>
     83       1.1  thorpej #include <sys/queue.h>
     84       1.1  thorpej #include <stdlib.h>
     85       1.1  thorpej #include <errno.h>
     86       1.1  thorpej #include <fcntl.h>
     87       1.1  thorpej #include <semaphore.h>
     88       1.1  thorpej #include <stdarg.h>
     89       1.1  thorpej 
     90       1.1  thorpej struct _sem_st {
     91       1.1  thorpej 	unsigned int	ksem_magic;
     92       1.1  thorpej #define	KSEM_MAGIC	0x90af0421U
     93       1.1  thorpej 
     94       1.1  thorpej 	LIST_ENTRY(_sem_st) ksem_list;
     95       1.1  thorpej 	semid_t		ksem_semid;	/* 0 -> user (non-shared) */
     96       1.1  thorpej 	sem_t		*ksem_identity;
     97       1.1  thorpej };
     98       1.1  thorpej 
     99       1.1  thorpej static int sem_alloc(unsigned int value, semid_t semid, sem_t *semp);
    100       1.1  thorpej static void sem_free(sem_t sem);
    101       1.1  thorpej 
    102       1.1  thorpej static LIST_HEAD(, _sem_st) named_sems = LIST_HEAD_INITIALIZER(&named_sems);
    103       1.1  thorpej 
    104       1.3   simonb #ifdef __weak_alias
    105       1.1  thorpej __weak_alias(sem_init,_librt_sem_init)
    106       1.1  thorpej __weak_alias(sem_destroy,_librt_sem_destroy)
    107       1.1  thorpej __weak_alias(sem_open,_librt_sem_open)
    108       1.1  thorpej __weak_alias(sem_close,_librt_sem_close)
    109       1.1  thorpej __weak_alias(sem_unlink,_librt_sem_unlink)
    110       1.1  thorpej __weak_alias(sem_wait,_librt_sem_wait)
    111       1.1  thorpej __weak_alias(sem_trywait,_librt_sem_trywait)
    112       1.1  thorpej __weak_alias(sem_post,_librt_sem_post)
    113       1.1  thorpej __weak_alias(sem_getvalue,_librt_sem_getvalue)
    114       1.3   simonb #endif
    115       1.1  thorpej 
    116       1.1  thorpej static void
    117       1.1  thorpej sem_free(sem_t sem)
    118       1.1  thorpej {
    119       1.1  thorpej 
    120       1.1  thorpej 	sem->ksem_magic = 0;
    121       1.1  thorpej 	free(sem);
    122       1.1  thorpej }
    123       1.1  thorpej 
    124       1.1  thorpej static int
    125       1.1  thorpej sem_alloc(unsigned int value, semid_t semid, sem_t *semp)
    126       1.1  thorpej {
    127       1.1  thorpej 	sem_t sem;
    128       1.1  thorpej 
    129       1.1  thorpej 	if (value > SEM_VALUE_MAX)
    130       1.1  thorpej 		return (EINVAL);
    131       1.1  thorpej 
    132       1.1  thorpej 	if ((sem = malloc(sizeof(struct _sem_st))) == NULL)
    133       1.1  thorpej 		return (ENOSPC);
    134       1.1  thorpej 
    135       1.1  thorpej 	sem->ksem_magic = KSEM_MAGIC;
    136       1.1  thorpej 	sem->ksem_semid = semid;
    137       1.1  thorpej 
    138       1.1  thorpej 	*semp = sem;
    139       1.1  thorpej 	return (0);
    140       1.1  thorpej }
    141       1.1  thorpej 
    142       1.1  thorpej /* ARGSUSED */
    143       1.1  thorpej int
    144       1.1  thorpej sem_init(sem_t *sem, int pshared, unsigned int value)
    145       1.1  thorpej {
    146       1.1  thorpej 	semid_t	semid;
    147       1.1  thorpej 	int error;
    148       1.1  thorpej 
    149       1.1  thorpej 	if (_ksem_init(value, &semid) == -1)
    150       1.1  thorpej 		return (-1);
    151       1.1  thorpej 
    152       1.1  thorpej 	if ((error = sem_alloc(value, semid, sem)) != 0) {
    153       1.1  thorpej 		_ksem_destroy(semid);
    154       1.1  thorpej 		errno = error;
    155       1.1  thorpej 		return (-1);
    156       1.1  thorpej 	}
    157       1.1  thorpej 
    158       1.1  thorpej 	return (0);
    159       1.1  thorpej }
    160       1.1  thorpej 
    161       1.1  thorpej int
    162       1.1  thorpej sem_destroy(sem_t *sem)
    163       1.1  thorpej {
    164       1.1  thorpej 
    165       1.1  thorpej #ifdef ERRORCHECK
    166       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    167       1.1  thorpej 		errno = EINVAL;
    168       1.1  thorpej 		return (-1);
    169       1.1  thorpej 	}
    170       1.1  thorpej #endif
    171       1.1  thorpej 
    172       1.1  thorpej 	if (_ksem_destroy((*sem)->ksem_semid) == -1)
    173       1.1  thorpej 		return (-1);
    174       1.1  thorpej 
    175       1.1  thorpej 	sem_free(*sem);
    176       1.1  thorpej 
    177       1.1  thorpej 	return (0);
    178       1.1  thorpej }
    179       1.1  thorpej 
    180       1.1  thorpej sem_t *
    181       1.1  thorpej sem_open(const char *name, int oflag, ...)
    182       1.1  thorpej {
    183       1.1  thorpej 	sem_t *sem, s;
    184       1.1  thorpej 	semid_t semid;
    185       1.1  thorpej 	mode_t mode;
    186       1.1  thorpej 	unsigned int value;
    187       1.1  thorpej 	int error;
    188       1.1  thorpej 	va_list ap;
    189       1.1  thorpej 
    190       1.1  thorpej 	mode = 0;
    191       1.1  thorpej 	value = 0;
    192       1.1  thorpej 
    193       1.1  thorpej 	if (oflag & O_CREAT) {
    194       1.1  thorpej 		va_start(ap, oflag);
    195       1.1  thorpej 		mode = va_arg(ap, int);
    196       1.1  thorpej 		value = va_arg(ap, unsigned int);
    197       1.1  thorpej 		va_end(ap);
    198       1.1  thorpej 	}
    199       1.1  thorpej 
    200       1.1  thorpej 	/*
    201       1.1  thorpej 	 * We can be lazy and let the kernel handle the oflag,
    202       1.1  thorpej 	 * we'll just merge duplicate IDs into our list.
    203       1.1  thorpej 	 */
    204       1.1  thorpej 	if (_ksem_open(name, oflag, mode, value, &semid) == -1)
    205       1.1  thorpej 		return (SEM_FAILED);
    206       1.1  thorpej 
    207       1.1  thorpej 	/*
    208       1.1  thorpej 	 * Search for a duplicate ID, we must return the same sem_t *
    209       1.1  thorpej 	 * if we locate one.
    210       1.1  thorpej 	 */
    211       1.1  thorpej 	LIST_FOREACH(s, &named_sems, ksem_list) {
    212       1.1  thorpej 		if (s->ksem_semid == semid)
    213       1.1  thorpej 			return (s->ksem_identity);
    214       1.1  thorpej 	}
    215       1.1  thorpej 
    216       1.1  thorpej 	if ((sem = malloc(sizeof(*sem))) == NULL) {
    217       1.1  thorpej 		error = ENOSPC;
    218       1.1  thorpej 		goto bad;
    219       1.1  thorpej 	}
    220       1.1  thorpej 	if ((error = sem_alloc(value, semid, sem)) != 0)
    221       1.1  thorpej 		goto bad;
    222       1.1  thorpej 
    223       1.1  thorpej 	LIST_INSERT_HEAD(&named_sems, *sem, ksem_list);
    224       1.1  thorpej 	(*sem)->ksem_identity = sem;
    225       1.1  thorpej 
    226       1.1  thorpej 	return (sem);
    227       1.1  thorpej 
    228       1.1  thorpej  bad:
    229       1.1  thorpej 	_ksem_close(semid);
    230       1.1  thorpej 	if (sem != NULL) {
    231       1.1  thorpej 		if (*sem != NULL)
    232       1.1  thorpej 			sem_free(*sem);
    233       1.1  thorpej 		free(sem);
    234       1.1  thorpej 	}
    235       1.1  thorpej 	errno = error;
    236       1.1  thorpej 	return (SEM_FAILED);
    237       1.1  thorpej }
    238       1.1  thorpej 
    239       1.1  thorpej int
    240       1.1  thorpej sem_close(sem_t *sem)
    241       1.1  thorpej {
    242       1.1  thorpej 
    243       1.1  thorpej #ifdef ERRORCHECK
    244       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    245       1.1  thorpej 		errno = EINVAL;
    246       1.1  thorpej 		return (-1);
    247       1.1  thorpej 	}
    248       1.1  thorpej #endif
    249       1.1  thorpej 
    250       1.1  thorpej 	if (_ksem_close((*sem)->ksem_semid) == -1)
    251       1.1  thorpej 		return (-1);
    252       1.1  thorpej 
    253       1.1  thorpej 	LIST_REMOVE((*sem), ksem_list);
    254       1.1  thorpej 	sem_free(*sem);
    255       1.1  thorpej 	free(sem);
    256       1.1  thorpej 	return (0);
    257       1.1  thorpej }
    258       1.1  thorpej 
    259       1.1  thorpej int
    260       1.1  thorpej sem_unlink(const char *name)
    261       1.1  thorpej {
    262       1.1  thorpej 
    263       1.1  thorpej 	return (_ksem_unlink(name));
    264       1.1  thorpej }
    265       1.1  thorpej 
    266       1.1  thorpej int
    267       1.1  thorpej sem_wait(sem_t *sem)
    268       1.1  thorpej {
    269       1.1  thorpej 
    270       1.1  thorpej #ifdef ERRORCHECK
    271       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    272       1.1  thorpej 		errno = EINVAL;
    273       1.1  thorpej 		return (-1);
    274       1.1  thorpej 	}
    275       1.1  thorpej #endif
    276       1.1  thorpej 
    277       1.1  thorpej 	return (_ksem_wait((*sem)->ksem_semid));
    278       1.1  thorpej }
    279       1.1  thorpej 
    280       1.1  thorpej int
    281       1.1  thorpej sem_trywait(sem_t *sem)
    282       1.1  thorpej {
    283       1.1  thorpej 
    284       1.1  thorpej #ifdef ERRORCHECK
    285       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    286       1.1  thorpej 		errno = EINVAL;
    287       1.1  thorpej 		return (-1);
    288       1.1  thorpej 	}
    289       1.1  thorpej #endif
    290       1.1  thorpej 
    291       1.1  thorpej 	return (_ksem_trywait((*sem)->ksem_semid));
    292       1.1  thorpej }
    293       1.1  thorpej 
    294       1.1  thorpej int
    295       1.1  thorpej sem_post(sem_t *sem)
    296       1.1  thorpej {
    297       1.1  thorpej 
    298       1.1  thorpej #ifdef ERRORCHECK
    299       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    300       1.1  thorpej 		errno = EINVAL;
    301       1.1  thorpej 		return (-1);
    302       1.1  thorpej 	}
    303       1.1  thorpej #endif
    304       1.1  thorpej 
    305       1.1  thorpej 	return (_ksem_post((*sem)->ksem_semid));
    306       1.1  thorpej }
    307       1.1  thorpej 
    308       1.1  thorpej int
    309       1.1  thorpej sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
    310       1.1  thorpej {
    311       1.1  thorpej 
    312       1.1  thorpej #ifdef ERRORCHECK
    313       1.1  thorpej 	if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
    314       1.1  thorpej 		errno = EINVAL;
    315       1.1  thorpej 		return (-1);
    316       1.1  thorpej 	}
    317       1.1  thorpej #endif
    318       1.1  thorpej 	return (_ksem_getvalue((*sem)->ksem_semid, sval));
    319       1.1  thorpej }
    320