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