1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17#include <stdio.h>
18#include <stdarg.h>
19#include <string.h>
20#include <sys/stat.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <unistd.h>
24#include <shared.h>
25#include "semaphore_mfp.h"
26
27semaphore_t Semaphore;
28semaphore_t spinlock[SPINLOCK_SPIN_MAX];
29
30int semaphore_create()
31{
32	int flag_sem = O_CREAT|O_RDWR;
33	int init_value = 1;
34
35	semaphore_unlink(SEM_NAME);
36
37	if (semaphore_open(SEM_NAME, flag_sem, FILE_MODE, init_value) == -1)
38	{
39		perror("semaphore_create fail");
40		return -1;
41	}
42
43	return 0;
44}
45
46int semaphore_close()
47{
48	if (Semaphore.sem_magic != SEM_MAGIC)
49	{
50		errno = EINVAL;
51		return -1;
52	}
53
54	Semaphore.sem_magic = 0;	// in case caller tries to use it later
55	if (close(Semaphore.sem_fd[0]) == -1 || close(Semaphore.sem_fd[1]) == -1)
56	{
57		memset(&Semaphore, '\0', sizeof(semaphore_t));
58		return -1;
59	}
60
61	memset(&Semaphore, '\0', sizeof(semaphore_t));
62	return 0;
63}
64
65int semaphore_open(const char *pathname, int oflag, ... )
66{
67	int	i, flags, save_errno;
68	char	c;
69	mode_t	mode;
70	va_list	ap;
71	unsigned int	value = 0;
72
73	if (oflag & O_CREAT)
74	{
75		va_start(ap, oflag);			// init ap to final named argument
76		mode = va_arg(ap, mode_t);
77		value = va_arg(ap, unsigned int);
78		va_end(ap);
79
80		if (mkfifo(pathname, mode) < 0)
81		{
82			if (errno == EEXIST && (oflag & O_EXCL) == 0)
83				oflag &= ~O_CREAT;      // already exists, OK
84			else
85			{
86				perror("Sen_open: mkfifo fail");
87				return -1;
88			}
89		}
90	}
91
92	Semaphore.sem_fd[0] = Semaphore.sem_fd[1] = -1;
93
94	if ( (Semaphore.sem_fd[0] = open(pathname, O_RDONLY | O_NONBLOCK)) < 0)
95		goto error;
96	if ( (Semaphore.sem_fd[1] = open(pathname, O_WRONLY | O_NONBLOCK)) < 0)
97		goto error;
98	if ( (flags = fcntl(Semaphore.sem_fd[0], F_GETFL, 0)) < 0)
99		goto error;
100	flags &= ~O_NONBLOCK;
101	if (fcntl(Semaphore.sem_fd[0], F_SETFL, flags) < 0)
102		goto error;
103	if (oflag & O_CREAT)	// initialize semaphore
104	{
105		for (i = 0; i < value; i++)
106			if (write(Semaphore.sem_fd[1], &c, 1) != 1)
107				goto error;
108	}
109
110	Semaphore.sem_magic = SEM_MAGIC;
111	return 0;
112
113error:
114	save_errno = errno;
115	if (oflag & O_CREAT)
116		unlink(pathname);		// if we created FIFO
117	close(Semaphore.sem_fd[0]);		// ignore error
118	close(Semaphore.sem_fd[1]);		// ignore error
119
120	memset(&Semaphore, '\0',sizeof(semaphore_t));
121	errno = save_errno;
122	perror("semaphore_open error");
123
124	return -1;
125}
126
127int semaphore_unlink(const char *pathname)
128{
129	return unlink(pathname);
130}
131
132int semaphore_post()
133{
134	char	c;
135
136	if (Semaphore.sem_magic != SEM_MAGIC)
137	{
138		errno = EINVAL;
139		return -1;
140	}
141
142	if (write(Semaphore.sem_fd[1], &c, 1) == 1)
143		return 0;
144
145	return -1;
146}
147
148int semaphore_wait()
149{
150	char	c;
151
152	if (Semaphore.sem_magic != SEM_MAGIC)
153	{
154		errno = EINVAL;
155		return -1;
156	}
157
158	if (read(Semaphore.sem_fd[0], &c, 1) == 1)
159		return 0;
160
161	return -1;
162}
163
164int spinlock_open(int idx, const char *pathname, int oflag, ... )
165{
166	int	i, flags, save_errno;
167	char	c;
168	mode_t	mode;
169	va_list	ap;
170	unsigned int	value = 0;
171
172	if (oflag & O_CREAT)
173	{
174		va_start(ap, oflag);			// init ap to final named argument
175		mode = va_arg(ap, mode_t);
176		value = va_arg(ap, unsigned int);
177		va_end(ap);
178
179		if (mkfifo(pathname, mode) < 0)
180		{
181			if (errno == EEXIST && (oflag & O_EXCL) == 0)
182				oflag &= ~O_CREAT;      // already exists, OK
183			else
184			{
185				perror("Sen_open: mkfifo fail");
186				return -1;
187			}
188		}
189	}
190
191	spinlock[idx].sem_fd[0] = spinlock[idx].sem_fd[1] = -1;
192
193	if ( (spinlock[idx].sem_fd[0] = open(pathname, O_RDONLY | O_NONBLOCK)) < 0)
194		goto error;
195	if ( (spinlock[idx].sem_fd[1] = open(pathname, O_WRONLY | O_NONBLOCK)) < 0)
196		goto error;
197	if ( (flags = fcntl(spinlock[idx].sem_fd[0], F_GETFL, 0)) < 0)
198		goto error;
199	flags &= ~O_NONBLOCK;
200	if (fcntl(spinlock[idx].sem_fd[0], F_SETFL, flags) < 0)
201		goto error;
202
203	if (oflag & O_CREAT)	// initialize semaphore
204	{
205		for (i = 0; i < value; i++)
206			if (write(spinlock[idx].sem_fd[1], &c, 1) != 1)
207				goto error;
208	}
209
210	spinlock[idx].sem_magic = SEM_MAGIC;
211	return 0;
212
213error:
214	save_errno = errno;
215	if (oflag & O_CREAT)
216		unlink(pathname);		// if we created FIFO
217	close(spinlock[idx].sem_fd[0]);		// ignore error
218	close(spinlock[idx].sem_fd[1]);		// ignore error
219
220	memset(&spinlock[idx], '\0',sizeof(semaphore_t));
221	errno = save_errno;
222	perror("semaphore_open error");
223
224	return -1;
225}
226
227int spinlock_init(int idx)
228{
229	int flag_sem = O_CREAT|O_RDWR;
230	int init_value = 1;
231	char sem_name[32];
232
233	if (idx < 0 || idx >= SPINLOCK_SPIN_MAX)
234		return -1;
235
236	sprintf(sem_name, "%s%d", SEM_NAME, idx);
237	semaphore_unlink(sem_name);
238
239	if (spinlock_open(idx, sem_name, flag_sem, FILE_MODE, init_value) == -1)
240	{
241		perror("semaphore_create fail");
242		return -1;
243	}
244
245	return 0;
246}
247
248int spinlock_destroy(int idx)
249{
250	if (idx < 0 || idx >= SPINLOCK_SPIN_MAX)
251		return -1;
252
253	if (spinlock[idx].sem_magic != SEM_MAGIC)
254	{
255		errno = EINVAL;
256		return -1;
257	}
258
259	spinlock[idx].sem_magic = 0;	// in case caller tries to use it later
260	if (close(spinlock[idx].sem_fd[0]) == -1 || close(spinlock[idx].sem_fd[1]) == -1)
261	{
262		memset(&spinlock[idx], '\0', sizeof(semaphore_t));
263		return -1;
264	}
265
266	memset(&spinlock[idx], '\0', sizeof(semaphore_t));
267	return 0;
268}
269
270void init_spinlock(void)
271{
272	int i;
273
274	for(i=0;i<SPINLOCK_SPIN_MAX;i++)
275		spinlock_init(i);
276}
277
278int spinlock_unlock(int idx)
279{
280	char	c;
281
282	if (idx < 0 || idx >= SPINLOCK_SPIN_MAX)
283		return -1;
284
285	if (spinlock[idx].sem_magic != SEM_MAGIC)
286	{
287		errno = EINVAL;
288		return -1;
289	}
290
291	if (write(spinlock[idx].sem_fd[1], &c, 1) == 1)
292		return 0;
293
294	return -1;
295}
296
297int spinlock_lock(int idx)
298{
299	char	c;
300
301	if (idx < 0 || idx >= SPINLOCK_SPIN_MAX)
302		return -1;
303
304	if (spinlock[idx].sem_magic != SEM_MAGIC)
305	{
306		errno = EINVAL;
307		return -1;
308	}
309
310	if (read(spinlock[idx].sem_fd[0], &c, 1) == 1)
311		return 0;
312
313	return -1;
314}
315