1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * xsem.c: to provide a semaphore system (used by the smq routines)
29  *
30  * these routines come from the libxposix library.
31  */
32 
33 #include <pthread.h>
34 #include <time.h>
35 
36 #include "xsem.h"
37 
38 
39 int
xsem_init(xsem_t * sem,int pshared,unsigned int value)40 xsem_init(xsem_t *sem, int pshared, unsigned int value)
41 {
42 	if (pshared != 0)
43 		return (-1);
44 
45 	pthread_mutex_init(&sem->semMutex, NULL);
46 	pthread_cond_init(&sem->semCV, NULL);
47 	sem->semaphore = value;
48 
49 	return (0);
50 }
51 
52 void
xsem_destroy(xsem_t * sem)53 xsem_destroy(xsem_t *sem)
54 {
55 	pthread_mutex_destroy(&sem->semMutex);
56 	pthread_cond_destroy(&sem->semCV);
57 	sem->semaphore = 0;
58 }
59 
60 int
xsem_wait(xsem_t * sem)61 xsem_wait(xsem_t *sem)
62 {
63 	pthread_mutex_lock(&sem->semMutex);
64 
65 	if (sem->semaphore < 0) {
66 		sem->semaphore = 0;
67 		pthread_mutex_unlock(&sem->semMutex);
68 		return (XSEM_ERROR);
69 	}
70 
71 	if (sem->semaphore > 0) {
72 		sem->semaphore--;
73 	} else {
74 		while (sem->semaphore == 0)
75 			pthread_cond_wait(&sem->semCV, &sem->semMutex);
76 
77 		if (sem->semaphore != 0) {
78 			sem->semaphore--;
79 		} else {
80 			pthread_mutex_unlock(&sem->semMutex);
81 			return (XSEM_ERROR);
82 		}
83 	}
84 
85 	pthread_mutex_unlock(&sem->semMutex);
86 	return (0);
87 }
88 
89 
90 int
xsem_trywait(xsem_t * sem)91 xsem_trywait(xsem_t *sem)
92 {
93 	pthread_mutex_lock(&sem->semMutex);
94 
95 	if (sem->semaphore < 0) {
96 		sem->semaphore = 0;
97 		pthread_mutex_unlock(&sem->semMutex);
98 		return (XSEM_ERROR);
99 	}
100 
101 	if (sem->semaphore == 0) {
102 		pthread_mutex_unlock(&sem->semMutex);
103 		return (XSEM_EBUSY);
104 	} else {
105 		sem->semaphore--;
106 	}
107 
108 	pthread_mutex_unlock(&sem->semMutex);
109 	return (0);
110 }
111 
112 
113 int
xsem_post(xsem_t * sem)114 xsem_post(xsem_t *sem)
115 {
116 	pthread_mutex_lock(&sem->semMutex);
117 	sem->semaphore++;
118 	pthread_cond_signal(&sem->semCV);
119 	pthread_mutex_unlock(&sem->semMutex);
120 
121 	return (0);
122 }
123 
124 
125 void
xsem_getvalue(xsem_t * sem,int * sval)126 xsem_getvalue(xsem_t *sem, int *sval)
127 {
128 	*sval = sem->semaphore;
129 }
130 
131 
132 
133 int
xsem_xwait(xsem_t * sem,int timeout,timestruc_t * mytime)134 xsem_xwait(xsem_t *sem, int timeout, timestruc_t *mytime)
135 {
136 	int		status;
137 	timestruc_t	delay;
138 
139 	if (timeout == 0)
140 		return (xsem_wait(sem));
141 	else {
142 		pthread_mutex_lock(&sem->semMutex);
143 
144 		if (sem->semaphore < 0) {
145 			sem->semaphore = 0;
146 			pthread_mutex_unlock(&sem->semMutex);
147 			return (XSEM_ERROR);
148 		}
149 
150 		if (sem->semaphore > 0) {
151 			sem->semaphore--;
152 		} else {
153 			status = 0;
154 
155 			delay  = *mytime;
156 			delay.tv_sec = delay.tv_sec + time(NULL);
157 			while ((sem->semaphore == 0) && (status == 0)) {
158 				status = pthread_cond_timedwait(&sem->semCV,
159 				    &sem->semMutex, &delay);
160 			}
161 
162 			/*
163 			 * Check one more time in case thread didn't have a
164 			 * chance to check before timeout ??? TBD
165 			 */
166 
167 			if (status != 0) {
168 				pthread_mutex_unlock(&sem->semMutex);
169 				return (XSEM_ETIME);
170 			} else if (sem->semaphore != 0) {
171 				sem->semaphore--;
172 			} else {
173 				pthread_mutex_unlock(&sem->semMutex);
174 				return (XSEM_ERROR);
175 			}
176 		}
177 
178 		pthread_mutex_unlock(&sem->semMutex);
179 	}
180 
181 	return (0);
182 }
183