1/*
2    Buffer.  Very fast reblocking filter speedy writing of tapes.
3    Copyright (C) 1990,1991  Lee McLoughlin
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 1, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19    Lee McLoughlin.
20    Dept of Computing, Imperial College,
21    180 Queens Gate, London, SW7 2BZ, UK.
22
23    Email: L.McLoughlin@doc.ic.ac.uk
24*/
25
26/* This is a simple module to provide an easier to understand interface to
27 * semaphores */
28
29#include <stdio.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/ipc.h>
33#include <sys/sem.h>
34#include <errno.h>
35#include "sem.h"
36
37#if defined(SYS5) || defined(ultrix) || defined(_AIX)
38union semun {
39	int val;
40	struct semid_ds *buf;
41	ushort *array;
42};
43#endif
44
45/* IMPORTS */
46
47/* Used to print error messages */
48extern void report_proc();
49
50/* Used to end the program - on error */
51extern void byee();
52
53
54
55/* Set a semaphore to a particular value - meant to be used before
56 * first lock/unlock */
57void
58sem_set( sem_id, semn, val )
59	int sem_id;
60	int semn;
61	int val;
62{
63	union semun arg;
64	extern int errno;
65
66	arg.val = val;
67
68	errno = 0;
69	semctl( sem_id, semn, SETVAL, arg );
70	if( errno != 0 ){
71		report_proc();
72		perror( "internal error, sem_set" );
73		byee( -1 );
74	}
75}
76
77int
78new_sems( nsems )
79	int nsems;
80{
81	int sem;
82	int i;
83
84	sem = semget( IPC_PRIVATE, nsems, IPC_CREAT|S_IREAD|S_IWRITE );
85	if( sem < 0 ){
86		report_proc();
87		perror( "internal error, couldn't create semaphore" );
88		byee( -1 );
89	}
90
91	for( i = 0; i < nsems; i++ ){
92		sem_set( sem, i, 1 );
93	}
94
95	return sem;
96}
97
98static
99do_sem( sem_id, pbuf, err )
100	int sem_id;
101	struct sembuf *pbuf;
102	char *err;
103{
104	/* This just keeps us going in case of EINTR */
105	while( 1 ){
106		if( semop( sem_id, pbuf, 1 ) == -1 ){
107			if( errno == EINTR ){
108				continue;
109			}
110			report_proc();
111			fprintf( stderr, "internal error pid %d, lock id %d\n",
112				getpid(), sem_id );
113			perror( err );
114			byee( -1 );
115		}
116		return;
117	}
118}
119
120void
121lock( sem_id, semn )
122	int sem_id;
123	int semn;
124{
125	struct sembuf sembuf;
126
127	sembuf.sem_num = semn;
128	sembuf.sem_op = -1;
129	sembuf.sem_flg = 0;
130
131	do_sem( sem_id, &sembuf, "lock error" );
132}
133
134void
135unlock( sem_id, semn )
136	int sem_id;
137	int semn;
138{
139	struct sembuf sembuf;
140
141	sembuf.sem_num = semn;
142	sembuf.sem_op = 1;
143	sembuf.sem_flg = 0;
144
145	do_sem( sem_id, &sembuf, "unlock error" );
146}
147
148void
149remove_sems( sem_id )
150	int sem_id;
151{
152	if( sem_id == -1 )
153		return;
154
155	if( semctl( sem_id, 0, IPC_RMID, NULL ) == -1 ){
156		report_proc();
157		perror( "internal error, failed to remove semaphore" );
158	}
159}
160