resetting manifest requested domain to floor
[platform/upstream/cdrkit.git] / icedax / semshm.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /*
14  * Copyright 1998-2002 Heiko Eissfeldt
15  */
16
17 #define IPCTST
18 #undef IPCTST
19 /* -------------------------------------------------------------------- */
20 /*        semshm.c                                                      */
21 /* -------------------------------------------------------------------- */
22 /*               int seminstall(key,amount)                             */
23 /*               int semrequest(semid,semnum)                           */
24 /*               int semrelease(semid,semnum)                           */
25 /* -------------------------------------------------------------------- */
26
27 #include "config.h"
28
29 #if     !defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && !defined(HAVE_DOSALLOCSHAREDMEM) && !defined(HAVE_AREAS)
30 #undef  FIFO                    /* We cannot have a FIFO on this platform */
31 #endif
32
33 #if !defined(USE_MMAP) && !defined(USE_USGSHM)
34 #define USE_MMAP
35 #endif
36
37 #if     !defined HAVE_SMMAP && defined FIFO
38 #       undef   USE_MMAP
39 #       define  USE_USGSHM      /* SYSV shared memory is the default    */
40 #endif
41
42 #ifdef  USE_MMAP                /* Only want to have one implementation */
43 #       undef   USE_USGSHM      /* mmap() is preferred                  */
44 #endif
45
46 #ifdef  HAVE_DOSALLOCSHAREDMEM
47 #       undef   USE_MMAP
48 #       undef   USE_USGSHM
49 #       define  USE_OS2SHM
50 #       undef   USE_BEOS_AREAS
51 #endif
52
53 #ifdef  HAVE_AREAS
54 #       undef   USE_MMAP
55 #       undef   USE_USGSHM
56 #       undef   USE_OS2SHM
57 #       define  USE_BEOS_AREAS
58 #endif
59
60 #include <stdio.h>
61 #include <stdxlib.h>
62 #include <unixstd.h>
63 #include <fctldefs.h>
64 #include <errno.h>
65 #include <standard.h>
66 #include <schily.h>
67
68 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
69 #include <sys/types.h>
70 #include <sys/ipc.h>
71 #include <sys/sem.h>
72 #endif
73
74 #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1)
75 #include <sys/types.h>
76 #include <sys/ipc.h>
77 #include <sys/shm.h>
78 #endif
79
80 #ifdef  USE_MMAP
81 #if defined(HAVE_SMMAP) && defined(USE_MMAP)
82 #include <mmapdefs.h>
83 #endif
84 #endif
85
86 #include <usal/scsitransp.h>
87
88 #ifdef  USE_BEOS_AREAS
89 #include        <be/kernel/OS.h>
90 #endif
91
92 #include "mytype.h"
93 #include "interface.h"
94 #include "ringbuff.h"
95 #include "global.h"
96 #include "exitcodes.h"
97 #include "semshm.h"
98
99 #ifdef DEBUG_SHM
100 char *start_of_shm;
101 char *end_of_shm;
102 #endif
103
104 int flush_buffers(void);
105
106
107 /*------ Semaphore interfacing (for special cases only) ----------*/
108 /*------ Synchronization with pipes is preferred        ----------*/
109
110 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
111
112 int sem_id;
113 static int seminstall(key_t key, int amount);
114
115 static int seminstall(key_t key, int amount)
116 {
117   int           ret_val;
118   int           semflag;
119
120   semflag = IPC_CREAT | 0600;
121 #ifdef IPCTST
122   fprintf(stderr,"seminstall: key: %d, #sems %d, flags %4x\n",
123           key,amount,semflag);
124 #endif
125   ret_val = semget(key,amount,semflag);
126   if ( ret_val == -1 )
127   {
128     fprintf(stderr,"semget: (Key %lx, #%d) failed: ",
129             (long)key,amount);
130     perror("");
131   }
132   return ret_val;
133 }
134
135 /*-----------------------------------------------------------------*/
136 int semrequest(int semid, int semnum)
137 {
138   struct sembuf sops[1];
139   int    ret_val;
140
141 #ifdef IPCTST
142   fprintf(stderr,"pid %d, ReQuest id:num %d:%d\n",getpid(),semid,semnum);
143 #endif
144   sops[0].sem_op  = -1;
145   sops[0].sem_num = (short) semnum;
146   sops[0].sem_flg = 0;
147
148   do {
149     errno = 0;
150     ret_val = semop(semid,sops,1);
151     if (ret_val == -1 && errno != EAGAIN && errno != EINTR)
152       {
153         fprintf(stderr,"Request Sema %d(%d) failed: ",semid,semnum);
154         perror("");
155       }
156   } while (errno == EAGAIN || errno == EINTR);
157   return(ret_val);
158 }
159
160 /*-----------------------------------------------------------------*/
161 int semrelease(int semid, int semnum, int amount)
162 {
163   struct sembuf sops[1];
164   int    ret_val;
165
166 #ifdef IPCTST
167   fprintf(stderr,"%d RL %d:%d\n",getpid(),semid,semnum);
168 #endif
169   sops[0].sem_op  = amount;
170   sops[0].sem_num = (short) semnum;
171   sops[0].sem_flg = 0;
172   ret_val = semop(semid,sops,1);
173   if ( ret_val == -1 && errno != EAGAIN)
174   {
175     fprintf(stderr,"Release Sema %d(%d) failed: ",semid,semnum);
176     perror("");
177   }
178   return(ret_val);
179 }
180
181 int flush_buffers()
182 {
183         return 0;
184 }
185 #else
186 /*------ Synchronization with pipes ----------*/
187 int pipefdp2c[2];
188 int pipefdc2p[2];
189
190 void init_pipes()
191 {
192   if (pipe(pipefdp2c) < 0) {
193     perror("cannot create pipe parent to child");
194     exit(PIPE_ERROR);
195   }
196   if (pipe(pipefdc2p) < 0) {
197     perror("cannot create pipe child to parent");
198     exit(PIPE_ERROR);
199   }
200 }
201
202 void init_parent()
203 {
204   close(pipefdp2c[0]);
205   close(pipefdc2p[1]);
206 }
207
208 void init_child()
209 {
210   close(pipefdp2c[1]);
211   close(pipefdc2p[0]);
212 }
213
214 int semrequest(int dummy, int semnum)
215 {
216
217   if (semnum == FREE_SEM /* 0 */)  {
218       int retval;
219     if ((*total_segments_read) - (*total_segments_written) >= global.buffers) {
220       /* parent/reader waits for freed buffers from the child/writer */
221       *parent_waits = 1;
222       retval = read(pipefdp2c[0], &dummy, 1) != 1;
223       return retval;
224     }
225   } else {
226       int retval;
227
228     if ((*total_segments_read) == (*total_segments_written)) {
229       /* child/writer waits for defined buffers from the parent/reader */
230       *child_waits = 1;
231       retval = read(pipefdc2p[0], &dummy, 1) != 1;
232       return retval;
233     }
234   }
235   return 0;
236 }
237
238 /* ARGSUSED */
239 int semrelease(int dummy, int semnum, int amount)
240 {
241   if (semnum == FREE_SEM /* 0 */)  {
242     if (*parent_waits == 1) {
243       int retval;
244       /* child/writer signals freed buffer to the parent/reader */
245       *parent_waits = 0;
246       retval = write(pipefdp2c[1], "12345678901234567890", amount) != amount;
247       return retval;
248     }
249   } else {
250     if (*child_waits == 1) {
251       int retval;
252       /* parent/reader signals defined buffers to the child/writer */
253       *child_waits = 0;
254       retval = write(pipefdc2p[1], "12345678901234567890", amount) != amount;
255       return retval;
256     }
257   }
258   return 0;
259 }
260
261 int flush_buffers()
262 {
263         if ((*total_segments_read) > (*total_segments_written)) {
264                 return write(pipefdc2p[1], "1", 1) != 1;
265         }
266         return 0;
267 }
268
269 #endif
270
271 /*------------------- Shared memory interfacing -----------------------*/
272
273
274
275 #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1)
276 static int shm_request_nommap(int size, unsigned char **memptr);
277
278 /* request a shared memory block */
279 static int shm_request_nommap(int size, unsigned char **memptr)
280 {
281   int   ret_val;
282   int   shmflag;
283   int   SHMEM_ID;
284   int    cmd;
285   struct shmid_ds buf;
286   key_t key = IPC_PRIVATE;
287
288   shmflag = IPC_CREAT | 0600;
289   ret_val = shmget(key,size,shmflag);
290   if ( ret_val == -1 )
291   {
292     perror("shmget");
293     return -1;
294   }
295
296   SHMEM_ID = ret_val;
297   cmd = IPC_STAT;
298   ret_val = shmctl(SHMEM_ID,cmd,&buf);
299 #ifdef IPCTST
300   fprintf(stderr, "%d: shmctl STAT= %d, SHM_ID: %d, key %ld cuid %d cgid %d mode %3o size %d\n",
301           getpid(),ret_val,SHMEM_ID,
302           (long) buf.shm_perm.key,buf.shm_perm.cuid,buf.shm_perm.cgid,
303           buf.shm_perm.mode,buf.shm_segsz);
304 #endif
305
306   *memptr = (unsigned char *) shmat(SHMEM_ID, NULL, 0);
307   if (*memptr == (unsigned char *) -1) {
308     *memptr = NULL;
309     fprintf( stderr, "shmat failed for %d bytes\n", size);
310     return -1;
311   }
312
313   if (shmctl(SHMEM_ID, IPC_RMID, 0) < 0) {
314     fprintf( stderr, "shmctl failed to detach shared memory segment\n");
315     return -1;
316   }
317
318
319 #ifdef DEBUG_SHM
320   start_of_shm = *memptr;
321   end_of_shm = (char *)(*memptr) + size;
322
323   fprintf(stderr, "Shared memory from %p to %p (%d bytes)\n", start_of_shm, end_of_shm, size);
324 #endif
325   return 0;
326 }
327
328
329 #endif  /* #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1) */
330
331
332 static int shm_request(int size, unsigned char **memptr);
333
334 #ifdef  USE_USGSHM
335 /* request a shared memory block */
336 static int shm_request(int size, unsigned char **memptr)
337 {
338         return shm_request_nommap(size, memptr);
339 }
340 #endif
341
342 /* release semaphores */
343 void free_sem(void);
344 void free_sem()
345 {
346 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
347   int   mycmd;
348   union my_semun unused_arg;
349
350   mycmd = IPC_RMID;
351
352   /* HP-UX warns here, but 'unused_arg' is not used for this operation */
353   /* This warning is difficult to avoid, since the structure of the union
354    * generally is not known (os dependent). So we cannot initialize it
355    * properly.
356    */
357   semctl(sem_id,0,mycmd,unused_arg);
358 #endif
359
360 }
361
362 #ifdef  USE_MMAP
363 #if defined(HAVE_SMMAP)
364
365 int shm_id;
366 /* request a shared memory block */
367 static int shm_request(int size, unsigned char **memptr)
368 {
369         int     f;
370         char    *addr;
371
372 #ifdef  MAP_ANONYMOUS   /* HP/UX */
373         f = -1;
374         addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, f, 0);
375 #else
376         if ((f = open("/dev/zero", O_RDWR)) < 0)
377                 comerr("Cannot open '/dev/zero'.\n");
378         addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
379 #endif
380
381         if (addr == (char *)-1) {
382 #if     defined HAVE_SHMAT && (HAVE_SHMAT == 1)
383                 unsigned char *address;
384                 /* fallback to alternate method */
385                 if (0 != shm_request_nommap(size, &address) || (addr = (char *)address) == NULL)
386 #endif
387                         comerr("Cannot get mmap for %d Bytes on /dev/zero.\n", size);
388         }
389         close(f);
390
391         if (memptr != NULL)
392                 *memptr = (unsigned char *)addr;
393
394         return 0;
395 }
396 #endif  /* HAVE_SMMAP */
397 #endif  /* USE_MMAP */
398
399 #ifdef  USE_OS2SHM
400
401 /* request a shared memory block */
402 static int shm_request(int size, unsigned char **memptr)
403 {
404         char    *addr;
405
406         /*
407          * The OS/2 implementation of shm (using shm.dll) limits the size of one
408          * memory segment to 0x3fa000 (aprox. 4MBytes). Using OS/2 native API we
409          * no such restriction so I decided to use it allowing fifos of arbitrary size
410          */
411         if(DosAllocSharedMem(&addr,NULL,size,0X100L | 0x1L | 0x2L | 0x10L))
412                 comerr("DosAllocSharedMem() failed\n");
413
414         if (memptr != NULL)
415                 *memptr = (unsigned char *)addr;
416
417         return 0;
418 }
419 #endif
420
421 #ifdef  USE_BEOS_AREAS
422
423 /* request a shared memory block */
424 static int shm_request(int size, unsigned char **memptr)
425 {
426         char    *addr;
427         area_id aid;    /* positive id of the mapping */
428
429         /* round up to a multiple of pagesize. */
430         size = ((size - 1) | (B_PAGE_SIZE - 1)) + 1;
431         /*
432          *      request a shared memory area in user space.
433          */
434         aid = create_area(AREA_NAME,    /* name of the mapping */
435                 (void *)&addr,          /* address of shared memory */
436                 B_ANY_ADDRESS,          /* type of address constraint */
437                 size,                   /* size in bytes (multiple of pagesize) */
438                 B_NO_LOCK, /* B_FULL_LOCK, */ /* memory locking */
439                 B_READ_AREA | B_WRITE_AREA);    /* read and write permissions */
440
441         if (aid < B_OK)
442                 comerrno(aid, "create_area() failed\n");
443
444         if (memptr != NULL)
445                 *memptr = (unsigned char *)addr;
446
447         return 0;
448 }
449 #endif
450
451 void *request_shm_sem(unsigned amount_of_sh_mem, unsigned char **pointer)
452 {
453 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
454     /* install semaphores for double buffer usage */
455     sem_id = seminstall(IPC_PRIVATE,2);
456     if ( sem_id == -1 ) {
457       perror("seminstall");
458       exit(SEMAPHORE_ERROR);
459     }
460
461 #endif
462
463 #if defined(FIFO)
464     if (-1 == shm_request(amount_of_sh_mem, pointer)) {
465         perror("shm_request");
466         exit(SHMMEM_ERROR);
467     }
468
469     return *pointer;
470 #else
471     return NULL;
472 #endif
473 }