1 /* @(#)semshm.c 1.33 16/02/14 Copyright 1998-2002 Heiko Eissfeldt, Copyright 2004-2013 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static	UConst char sccsid[] =
5 "@(#)semshm.c	1.33 16/02/14 Copyright 1998-2002 Heiko Eissfeldt, Copyright 2004-2013 J. Schilling";
6 #endif
7 
8 #define	IPCTST
9 #undef IPCTST
10 /* -------------------------------------------------------------------- */
11 /*	semshm.c							*/
12 /* -------------------------------------------------------------------- */
13 /*		int seminstall(key,amount)				*/
14 /*		int semrequest(semid,semnum)				*/
15 /*		int semrelease(semid,semnum)				*/
16 /* -------------------------------------------------------------------- */
17 /*
18  * The contents of this file are subject to the terms of the
19  * Common Development and Distribution License, Version 1.0 only
20  * (the "License").  You may not use this file except in compliance
21  * with the License.
22  *
23  * See the file CDDL.Schily.txt in this distribution for details.
24  * A copy of the CDDL is also available via the Internet at
25  * http://www.opensource.org/licenses/cddl1.txt
26  *
27  * When distributing Covered Code, include this CDDL HEADER in each
28  * file and include the License file CDDL.Schily.txt from this distribution.
29  */
30 
31 #include "config.h"
32 
33 #if	!defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && \
34 	!defined(HAVE_DOSALLOCSHAREDMEM) && !defined(HAVE_AREAS)
35 #undef  FIFO			/* We cannot have a FIFO on this platform */
36 #endif
37 
38 #if !defined(USE_MMAP) && !defined(USE_USGSHM)
39 #define	USE_MMAP
40 #endif
41 
42 #if	!defined HAVE_SMMAP && defined FIFO
43 #	undef   USE_MMAP
44 #	define  USE_USGSHM	/* SYSV shared memory is the default	*/
45 #endif
46 
47 #ifdef  USE_MMAP		/* Only want to have one implementation	*/
48 #	undef   USE_USGSHM	/* mmap() is preferred			*/
49 #endif
50 
51 #ifdef	HAVE_DOSALLOCSHAREDMEM
52 #	undef   USE_MMAP
53 #	undef   USE_USGSHM
54 #	define	USE_OS2SHM
55 #	undef	USE_BEOS_AREAS
56 #endif
57 
58 #ifdef	HAVE_AREAS
59 #	undef   USE_MMAP
60 #	undef   USE_USGSHM
61 #	undef	USE_OS2SHM
62 #	define	USE_BEOS_AREAS
63 #endif
64 
65 #include <schily/stdio.h>
66 #include <schily/stdlib.h>
67 #include <schily/unistd.h>
68 #include <schily/fcntl.h>
69 #include <schily/errno.h>
70 #include <schily/standard.h>
71 #include <schily/nlsdefs.h>
72 
73 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
74 #include <schily/types.h>
75 #include <schily/ipc.h>
76 #include <schily/sem.h>
77 #endif
78 
79 #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1)
80 #include <schily/types.h>
81 #include <schily/ipc.h>
82 #include <schily/shm.h>
83 #endif
84 
85 #ifdef  USE_MMAP
86 #if defined(HAVE_SMMAP) && defined(USE_MMAP)
87 #include <schily/mman.h>
88 #endif
89 #endif
90 #include <schily/schily.h>
91 
92 #include <scg/scsitransp.h>
93 
94 #ifdef	USE_BEOS_AREAS
95 #ifdef	HAVE_OS_H
96 #include	<OS.h>
97 #else
98 #include	<be/kernel/OS.h>
99 #endif
100 #endif
101 
102 #include "mytype.h"
103 #include "interface.h"
104 #include "ringbuff.h"
105 #include "global.h"
106 #include "exitcodes.h"
107 #include "semshm.h"
108 
109 #ifdef DEBUG_SHM
110 char	*start_of_shm;
111 char	*end_of_shm;
112 #endif
113 
114 int	flush_buffers	__PR((void));
115 
116 
117 /* ------ Semaphore interfacing (for special cases only)	---------- */
118 /* ------ Synchronization with pipes is preferred	---------- */
119 
120 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
121 
122 int sem_id;
123 static int	seminstall	__PR((key_t key, int amount));
124 
125 static int
seminstall(key,amount)126 seminstall(key, amount)
127 	key_t	key;
128 	int	amount;
129 {
130 	int	ret_val;
131 	int	semflag;
132 
133 	semflag = IPC_CREAT | 0600;
134 #ifdef IPCTST
135 	fprintf(stderr,
136 		"seminstall: key: %d, #sems %d, flags %4x\n",
137 		key, amount, semflag);
138 #endif
139 	ret_val = semget(key, amount, semflag);
140 	if (ret_val == -1) {
141 		errmsg(_("Semget: (Key %lx, #%d) failed.\n"),
142 			(long)key, amount);
143 	}
144 	return (ret_val);
145 }
146 
147 /* ----------------------------------------------------------------- */
148 int
semrequest(semid,semnum)149 semrequest(semid, semnum)
150 	int	semid;
151 	int	semnum;
152 {
153 	struct sembuf	sops[1];
154 	int		ret_val;
155 
156 #ifdef IPCTST
157 	fprintf(stderr, "pid %d, ReQuest id:num %d:%d\n",
158 			getpid(), semid, semnum);
159 #endif
160 	if (!global.have_forked)
161 		return (0);
162 	sops[0].sem_op  = -1;
163 	sops[0].sem_num = (short) semnum;
164 	sops[0].sem_flg = 0;
165 
166 	do {
167 		errno = 0;
168 		ret_val = semop(semid, sops, 1);
169 		if (ret_val == -1 && errno != EAGAIN && errno != EINTR) {
170 			errmsg(_("Request Sema %d(%d) failed.\n"),
171 				semid, semnum);
172 		}
173 	} while (errno == EAGAIN || errno == EINTR);
174 	return (ret_val);
175 }
176 
177 /* ----------------------------------------------------------------- */
178 int
semrelease(semid,semnum,amount)179 semrelease(semid, semnum, amount)
180 	int	semid;
181 	int	semnum;
182 	int	amount;
183 {
184 	struct sembuf	sops[1];
185 	int		ret_val;
186 
187 #ifdef IPCTST
188 	fprintf(stderr, "%d RL %d:%d\n", getpid(), semid, semnum);
189 #endif
190 	if (!global.have_forked)
191 		return (0);
192 	sops[0].sem_op  = amount;
193 	sops[0].sem_num = (short) semnum;
194 	sops[0].sem_flg = 0;
195 	ret_val = semop(semid, sops, 1);
196 	if (ret_val == -1 && errno != EAGAIN) {
197 		errmsg(_("Release Sema %d(%d) failed.\n"),
198 			semid, semnum);
199 	}
200 	return (ret_val);
201 }
202 
203 void
semdestroy()204 semdestroy()
205 {
206 	/*
207 	 * How do we stop the other process from waiting?
208 	 */
209 	free_sem();
210 }
211 
212 int
flush_buffers()213 flush_buffers()
214 {
215 	return (0);
216 }
217 #else
218 /* ------ Synchronization with pipes ---------- */
219 int	pipefdp2c[2];
220 int	pipefdc2p[2];
221 
222 void
init_pipes()223 init_pipes()
224 {
225 	if (pipe(pipefdp2c) < 0) {
226 		errmsg(_("Cannot create pipe parent to child.\n"));
227 		exit(PIPE_ERROR);
228 	}
229 	if (pipe(pipefdc2p) < 0) {
230 		errmsg(_("Cannot create pipe child to parent.\n"));
231 		exit(PIPE_ERROR);
232 	}
233 }
234 
235 void
init_parent()236 init_parent()
237 {
238 	close(pipefdp2c[0]);
239 	close(pipefdc2p[1]);
240 }
241 
242 void
init_child()243 init_child()
244 {
245 	close(pipefdp2c[1]);
246 	close(pipefdc2p[0]);
247 }
248 
249 int
semrequest(dummy,semnum)250 semrequest(dummy, semnum)
251 	int	dummy;
252 	int	semnum;
253 {
254 	if (!global.have_forked)
255 		return (0);
256 	if (semnum == FREE_SEM /* 0 */)  {
257 		if ((*total_segments_read) - (*total_segments_written) >=
258 		    global.buffers) {
259 			int	retval;
260 
261 			/*
262 			 * parent/reader waits for freed buffers from the
263 			 * child/writer
264 			 */
265 			*parent_waits = 1;
266 			retval = read(pipefdp2c[0], &dummy, 1) != 1;
267 			return (retval);
268 		}
269 	} else {
270 		if ((*total_segments_read) == (*total_segments_written)) {
271 			int	retval;
272 
273 			/*
274 			 * child/writer waits for defined buffers from the
275 			 * parent/reader
276 			 */
277 			*child_waits = 1;
278 			retval = read(pipefdc2p[0], &dummy, 1) != 1;
279 			return (retval);
280 		}
281 	}
282 	return (0);
283 }
284 
285 /* ARGSUSED */
286 int
semrelease(dummy,semnum,amount)287 semrelease(dummy, semnum, amount)
288 	int	dummy;
289 	int	semnum;
290 	int	amount;
291 {
292 	if (!global.have_forked)
293 		return (0);
294 	if (semnum == FREE_SEM /* 0 */)  {
295 		if (*parent_waits == 1) {
296 			int	retval;
297 
298 			/*
299 			 * child/writer signals freed buffer to the
300 			 * parent/reader
301 			 */
302 			*parent_waits = 0;
303 			retval = write(pipefdp2c[1],
304 					"12345678901234567890",
305 					amount) != amount;
306 			return (retval);
307 		}
308 	} else {
309 		if (*child_waits == 1) {
310 			int	retval;
311 
312 			/*
313 			 * parent/reader signals defined buffers to the
314 			 * child/writer
315 			 */
316 			*child_waits = 0;
317 			retval = write(pipefdc2p[1],
318 					"12345678901234567890",
319 					amount) != amount;
320 			return (retval);
321 		}
322 	}
323 	return (0);
324 }
325 
326 void
semdestroy()327 semdestroy()
328 {
329 	if (global.child_pid == 0) {	/* Child */
330 		close(pipefdp2c[1]);
331 		close(pipefdc2p[0]);
332 	} else if (global.child_pid != -1) {
333 		close(pipefdp2c[0]);
334 		close(pipefdc2p[1]);
335 	}
336 }
337 
338 
339 int
flush_buffers()340 flush_buffers()
341 {
342 	if ((*total_segments_read) > (*total_segments_written)) {
343 		return (write(pipefdc2p[1], "1", 1) != 1);
344 	}
345 	return (0);
346 }
347 
348 #endif
349 
350 /* ------------------- Shared memory interfacing ----------------------- */
351 
352 
353 
354 #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1)
355 static int shm_request_nommap	__PR((int size, unsigned char **memptr));
356 
357 /* request a shared memory block */
358 static int
shm_request_nommap(size,memptr)359 shm_request_nommap(size, memptr)
360 	int		size;
361 	unsigned char	**memptr;
362 {
363 	int	ret_val;
364 	int	shmflag;
365 	int	SHMEM_ID;
366 	int	cmd;
367 	struct shmid_ds	buf;
368 	key_t		key = IPC_PRIVATE;
369 
370 	shmflag = IPC_CREAT | 0600;
371 	ret_val = shmget(key, size, shmflag);
372 	if (ret_val == -1) {
373 		errmsg(_("Shmget failed.\n"));
374 		return (-1);
375 	}
376 
377 	SHMEM_ID = ret_val;
378 	cmd = IPC_STAT;
379 	ret_val = shmctl(SHMEM_ID, cmd, &buf);
380 #ifdef IPCTST
381 	fprintf(stderr,
382 	"%d: shmctl STAT= %d, SHM_ID: %d, key %ld cuid %d cgid %d mode %3o size %d\n",
383 		getpid(), ret_val, SHMEM_ID,
384 		(long) buf.shm_perm.key,
385 		buf.shm_perm.cuid, buf.shm_perm.cgid,
386 		buf.shm_perm.mode, buf.shm_segsz);
387 #endif
388 	if (ret_val == -1) {
389 		errmsg(_("Shmctl failed.\n"));
390 		return (-1);
391 	}
392 
393 	*memptr = (unsigned char *) shmat(SHMEM_ID, NULL, 0);
394 	if (*memptr == (unsigned char *) -1) {
395 		*memptr = NULL;
396 		errmsg(_("Shmat failed for %d bytes.\n"), size);
397 		return (-1);
398 	}
399 
400 	if (shmctl(SHMEM_ID, IPC_RMID, 0) < 0) {
401 		errmsg(_("Shmctl failed to detach shared memory segment.\n"));
402 		return (-1);
403 	}
404 
405 
406 #ifdef DEBUG_SHM
407 	start_of_shm = *memptr;
408 	end_of_shm = (char *)(*memptr) + size;
409 
410 	fprintf(stderr,
411 	"Shared memory from %p to %p (%d bytes)\n", start_of_shm, end_of_shm, size);
412 #endif
413 	return (0);
414 }
415 
416 
417 #endif	/* #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1) */
418 
419 
420 static int shm_request	__PR((int size, unsigned char **memptr));
421 
422 #ifdef  USE_USGSHM
423 /*
424  * request a shared memory block
425  */
426 static int
shm_request(size,memptr)427 shm_request(size, memptr)
428 	int		size;
429 	unsigned char	**memptr;
430 {
431 	return (shm_request_nommap(size, memptr));
432 }
433 #endif
434 
435 /*
436  * release semaphores
437  */
438 void	free_sem	__PR((void));
439 void
free_sem()440 free_sem()
441 {
442 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
443 	int		mycmd;
444 	union my_semun	unused_arg;
445 
446 	mycmd = IPC_RMID;
447 
448 	/*
449 	 * HP-UX warns here, but 'unused_arg' is not used for this operation
450 	 * This warning is difficult to avoid, since the structure of the union
451 	 * generally is not known (os dependent). So we cannot initialize it
452 	 * properly.
453 	 */
454 	semctl(sem_id, 0, mycmd, unused_arg);
455 #endif
456 
457 }
458 
459 #ifdef  USE_MMAP
460 #if defined(HAVE_SMMAP)
461 
462 int shm_id;
463 /*
464  * request a shared memory block
465  */
466 static int
shm_request(size,memptr)467 shm_request(size, memptr)
468 	int		size;
469 	unsigned char	**memptr;
470 {
471 	int	f;
472 	char	*addr;
473 
474 #ifdef  MAP_ANONYMOUS   /* HP/UX */
475 	f = -1;
476 	addr = mmap(0, mmap_sizeparm(size),
477 					PROT_READ|PROT_WRITE,
478 					MAP_SHARED|MAP_ANONYMOUS, f, 0);
479 #else
480 	if ((f = open("/dev/zero", O_RDWR)) < 0)
481 		comerr(_("Cannot open '/dev/zero'.\n"));
482 	addr = mmap(0, mmap_sizeparm(size),
483 					PROT_READ|PROT_WRITE,
484 					MAP_SHARED, f, 0);
485 #endif
486 
487 	if (addr == (char *)-1) {
488 #if	defined HAVE_SHMAT && (HAVE_SHMAT == 1)
489 		unsigned char *address;
490 		/* fallback to alternate method */
491 		if (0 != shm_request_nommap(size, &address) ||
492 		    (addr = (char *)address) == NULL)
493 #endif
494 			comerr(_("Cannot get mmap for %d Bytes on /dev/zero.\n"),
495 				size);
496 	}
497 	close(f);
498 
499 	if (memptr != NULL)
500 		*memptr = (unsigned char *)addr;
501 
502 	return (0);
503 }
504 #endif	/* HAVE_SMMAP */
505 #endif	/* USE_MMAP */
506 
507 #ifdef	USE_OS2SHM
508 
509 /*
510  * request a shared memory block
511  */
512 static int
shm_request(size,memptr)513 shm_request(size, memptr)
514 	int		size;
515 	unsigned char	**memptr;
516 {
517 	char	*addr;
518 
519 	/*
520 	 * The OS/2 implementation of shm (using shm.dll) limits the size
521 	 * of one memory segment to 0x3fa000 (aprox. 4MBytes).
522 	 * Using OS/2 native API we no such restriction so I decided to use
523 	 * it allowing fifos of arbitrary size
524 	 */
525 	if (DosAllocSharedMem(&addr, NULL, size, 0X100L | 0x1L | 0x2L | 0x10L))
526 		comerr(_("DosAllocSharedMem() failed\n"));
527 
528 	if (memptr != NULL)
529 		*memptr = (unsigned char *)addr;
530 
531 	return (0);
532 }
533 #endif
534 
535 #ifdef	USE_BEOS_AREAS
536 
537 /*
538  * request a shared memory block
539  */
540 static int
shm_request(size,memptr)541 shm_request(size, memptr)
542 	int		size;
543 	unsigned char	**memptr;
544 {
545 	char	*addr;
546 	area_id	aid;	/* positive id of the mapping */
547 
548 	/*
549 	 * round up to a multiple of pagesize.
550 	 */
551 	size = ((size - 1) | (B_PAGE_SIZE - 1)) + 1;
552 	/*
553 	 * request a shared memory area in user space.
554 	 */
555 	aid = create_area(AREA_NAME,	/* name of the mapping */
556 		(void *)&addr,		/* address of shared memory */
557 		B_ANY_ADDRESS,		/* type of address constraint */
558 		size,			/* size in bytes (multiple of pagesize) */
559 		B_NO_LOCK, /* B_FULL_LOCK, */ /* memory locking */
560 		B_READ_AREA | B_WRITE_AREA);	/* read and write permissions */
561 
562 	if (aid < B_OK)
563 		comerrno(aid, _("create_area() failed\n"));
564 
565 	if (memptr != NULL)
566 		*memptr = (unsigned char *)addr;
567 
568 	return (0);
569 }
570 #endif
571 
572 void *
request_shm_sem(amount_of_sh_mem,pointer)573 request_shm_sem(amount_of_sh_mem, pointer)
574 	unsigned	amount_of_sh_mem;
575 	unsigned char	**pointer;
576 {
577 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
578 	/*
579 	 * install semaphores for double buffer usage
580 	 */
581 	sem_id = seminstall(IPC_PRIVATE, 2);
582 	if (sem_id == -1) {
583 		errmsg(_("Seminstall failed.\n"));
584 		exit(SEMAPHORE_ERROR);
585 	}
586 
587 #endif
588 
589 #if defined(FIFO)
590 	if (-1 == shm_request(amount_of_sh_mem, pointer)) {
591 		errmsg(_("Shm_request failed.\n"));
592 		exit(SHMMEM_ERROR);
593 	}
594 
595 	return (*pointer);
596 #else
597 	return (NULL);
598 #endif
599 }
600