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 <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/ipc.h>
34 #include <sys/sem.h>
35 #include <errno.h>
36 #include "sem.h"
37 
38 #if defined(SYS5) || defined(ultrix) || defined(_AIX) || defined _SEM_SEMUN_UNDEFINED
39 union semun {
40 	int val;
41 	struct semid_ds *buf;
42 	ushort *array;
43 };
44 #endif
45 
46 /* IMPORTS */
47 
48 /* Used to print error messages */
49 extern void report_proc();
50 
51 /* Used to end the program - on error */
52 extern void byee();
53 
54 
55 
56 /* Set a semaphore to a particular value - meant to be used before
57  * first lock/unlock */
58 void
sem_set(sem_id,semn,val)59 sem_set( sem_id, semn, val )
60 	int sem_id;
61 	int semn;
62 	int val;
63 {
64 	union semun arg;
65 	extern int errno;
66 
67 	arg.val = val;
68 
69 	errno = 0;
70 	semctl( sem_id, semn, SETVAL, arg );
71 	if( errno != 0 ){
72 		report_proc();
73 		perror( "internal error, sem_set" );
74 		byee( -1 );
75 	}
76 }
77 
78 int
new_sems(nsems)79 new_sems( nsems )
80 	int nsems;
81 {
82 	int sem;
83 	int i;
84 
85 	sem = semget( IPC_PRIVATE, nsems, IPC_CREAT|S_IREAD|S_IWRITE );
86 	if( sem < 0 ){
87 		report_proc();
88 		perror( "internal error, couldn't create semaphore" );
89 		byee( -1 );
90 	}
91 
92 	for( i = 0; i < nsems; i++ ){
93 		sem_set( sem, i, 1 );
94 	}
95 
96 	return sem;
97 }
98 
99 static void
do_sem(sem_id,pbuf,err)100 do_sem( sem_id, pbuf, err )
101 	int sem_id;
102 	struct sembuf *pbuf;
103 	char *err;
104 {
105 	/* This just keeps us going in case of EINTR */
106 	while( 1 ){
107 		if( semop( sem_id, pbuf, 1 ) == -1 ){
108 			if( errno == EINTR ){
109 				continue;
110 			}
111 			report_proc();
112 			fprintf( stderr, "internal error pid %d, lock id %d\n",
113 				getpid(), sem_id );
114 			perror( err );
115 			byee( -1 );
116 		}
117 		return;
118 	}
119 }
120 
121 void
lock(sem_id,semn)122 lock( sem_id, semn )
123 	int sem_id;
124 	int semn;
125 {
126 	struct sembuf sembuf;
127 
128 	sembuf.sem_num = semn;
129 	sembuf.sem_op = -1;
130 	sembuf.sem_flg = 0;
131 
132 	do_sem( sem_id, &sembuf, "lock error" );
133 }
134 
135 void
unlock(sem_id,semn)136 unlock( sem_id, semn )
137 	int sem_id;
138 	int semn;
139 {
140 	struct sembuf sembuf;
141 
142 	sembuf.sem_num = semn;
143 	sembuf.sem_op = 1;
144 	sembuf.sem_flg = 0;
145 
146 	do_sem( sem_id, &sembuf, "unlock error" );
147 }
148 
149 void
remove_sems(sem_id)150 remove_sems( sem_id )
151 	int sem_id;
152 {
153 	if( sem_id == -1 )
154 		return;
155 
156 	if( semctl( sem_id, 0, IPC_RMID, (union semun)0 ) == -1 ){
157 		report_proc();
158 		perror( "internal error, failed to remove semaphore" );
159 	}
160 }
161