#include #include #include #include #include #include #if defined(ns32000) || defined(mips) || defined(__alpha) union semun { int val; struct semid_ds *buf; u_short *array; }; #endif extern int errno; #define MAXSEM 15 /* maximum number of semaphores */ static int semBase = -1; /* base semaphore value */ static int cSem = 0; /* count of current semaphores */ static int iSem = 0; /* current index of semaphore to use */ static int rgSem[MAXSEM]; /* keep track of semaphores used */ /* * swait() - wait on the given semaphore. Return -1 on error, zero on * success. */ swait(int sem) { struct sembuf sembuf; sembuf.sem_num = sem; sembuf.sem_op = -1; sembuf.sem_flg = 0; while (semop(semBase, &sembuf, 1) == -1) { if (errno != EINTR) return(-1); /* do not return on an interrupted wait */ } return(0); } /* * swaitn() - wait on the given semaphore for the given count. Return -1 on * error, zero on success. */ swaitn(int sem, int cnt) { struct sembuf sembuf; if (cnt <= 0) return(0); /* return immediately */ sembuf.sem_num = sem; sembuf.sem_op = -cnt; sembuf.sem_flg = 0; while (semop(semBase, &sembuf, 1) == -1) { if (errno != EINTR) return(-1); /* do not return on an interrupted wait */ } return(0); } /* * ssignal() - signal the given semaphore. Returns -1 on failure. */ ssignal(int sem) { struct sembuf sembuf; sembuf.sem_num = sem; sembuf.sem_op = 1; sembuf.sem_flg = 0; return(semop(semBase, &sembuf, 1)); } /* * ssignaln() - signal the given semaphore, the given number of times. Returns * -1 on failure. */ ssignaln(int sem, int cnt) { struct sembuf sembuf; if (cnt <= 0) return(0); /* return immediately */ sembuf.sem_num = sem; sembuf.sem_op = cnt; sembuf.sem_flg = 0; return(semop(semBase, &sembuf, 1)); } /* * screate() - create a semaphore with the given initial count. Returns -1 * on failure, a semaphore id on success. We have imposed a limit 12 * semaphores that can be created. */ screate(int cnt) { union semun arg; key_t key; static int iUniq = 0; if (iSem >= MAXSEM) return(-1); /* have reached semaphore limit */ if (semBase == -1) { /* need to get a chunk of semaphores */ /* give each user their own key */ key = getuid(); key = (key<<16) + iUniq++; if ((semBase = semget(key, MAXSEM, 0660|IPC_CREAT|IPC_EXCL)) < 0) { if (errno != EEXIST) return(-1); else { /* semaphore already exists, so delete and try again */ if ((semBase = semget(key, MAXSEM, 0660)) < 0) return(-1); /* problems if we try to just reuse, corruption on core dump?? */ (void)semctl(semBase, 0, IPC_RMID, (union semun *)NULL); if ((semBase = semget(key, MAXSEM, 0660|IPC_CREAT|IPC_EXCL)) < 0) return(0); } } } /* ok, at this point we have a set of semaphores */ arg.val = cnt; if (semctl(semBase, iSem, SETVAL, arg) < 0) { if (cSem == 0) (void)semctl(semBase, 0, IPC_RMID, (union semun *)NULL); return(-1); } rgSem[iSem] = iSem; /* put index value into array */ cSem++; iSem++; return(iSem-1); } /* * sdelete() - delete the semaphore corresponding to the given sem id. Returns * -1 on failure, zero on success. */ sdelete(int sem) { int ret; /* note we are not trying to reuse semaphore slots so we do nothing with iSem */ if (rgSem[sem] != sem) return(-1); /* does not match up with what it should */ ret = 0; if (cSem <= 1) { ret = semctl(semBase, 0, IPC_RMID, (union semun *)NULL); if (ret == 0) semBase = -1; } if (ret == 0) { cSem--; rgSem[sem] = -1; /* no longer in use */ } return(ret); } /* * scount() - return the count of the given sem id. -1 on failure. */ scount(int sem) { return(semctl(semBase, sem, GETVAL, (union semun *)NULL)); } /* * sreset() - reset the count of the given sem id. Return -1 on failure, * zero on success. */ sreset(int sem, int cnt) { union semun arg; /* need to free up processes in the queue, before reseting the count. need to check manual page to see if this action really happens, otherwise we need to do it. */ arg.val = cnt; return(semctl(semBase, sem, SETVAL, arg)); } /**************************************************************************/ #define MAXSHM 20 /* maximum number of memory chunks */ #define MAXMEM 1024 /* maximum amount of memory to be used */ static int cShm = 0; /* count of shared memory regions */ static int cByteOffset = 0; /* byte offset from sbShm */ static char *sbShmBase = (char *)-1; /* base location of shared memory chunk */ static int shm = -1; /* shm value for shared memory chunk */ static char *rgsbShm[MAXSHM]; /* keep track of memory pointers */ /* * shmcreate() - create the given amount of shared memory and return the * pointer to this memory. Return -1 on failure. We have imposed * a limit of 1024 bytes for the total amount of shared memory created. */ char *shmcreate(int cnt) { key_t key; int i; static int iUniq = 0; if (cShm >= MAXSHM) return((char *)-1); /* no more room to remember */ if (sbShmBase == (char *)-1) { /* need to get a shared memory chunk */ if (cnt > MAXMEM) return((char *)-1); /* will never get this much room */ /* give each user their own key */ key = getuid(); key = (key<<16) + iUniq++; if ((shm = shmget(key, MAXMEM, 0660|IPC_CREAT|IPC_EXCL)) < 0) { if (errno != EEXIST) return((char *)-1); else { /* shared memory already exists, so delete and try again */ if ((shm = shmget(key, MAXMEM, 0660)) < 0) return((char *)-1); /* problems if we just tried to attach to old shared memory after previous core dump---corruption?? */ (void)shmctl(shm, IPC_RMID, (struct shmid_ds *)NULL); if ((shm = shmget(key, MAXMEM, 0660|IPC_CREAT|IPC_EXCL)) < 0) return((char *)-1); } } /* cast from char * to long for alpha */ if ((long)(sbShmBase = (char *)shmat(shm, NULL, 0)) == -1) { /* a problem */ (void)shmctl(shm, IPC_RMID, (struct shmid_ds *)NULL); return((char *)-1); } } /* ok if we get to this point then we have a shared memory chunk */ if ((cByteOffset + cnt) > MAXMEM) return((char *)-1); /* more memory than we have */ else { /* remember this offset */ for (i = 0; i < cShm; i++) if (rgsbShm[i] == (char *)-1) break; rgsbShm[i] = &sbShmBase[cByteOffset]; cShm++; /* one more mapping */ if (cnt%8 == 0) cByteOffset += cnt; /* just update offset by the number of bytes */ else cByteOffset += cnt + 8 - cnt%8; /* make divisible by 8 */ return(rgsbShm[i]); } } /* * shmdelete() - delete the shared memory associated with the given address. * Return -1 on failure, zero on success. */ shmdelete(char *sbShm) { int i, ret; for (i = 0; i < MAXSHM; i++) { if (rgsbShm[i] == sbShm) { /* note we do not try and do compaction of the space! */ ret = 0; if (cShm <= 1) { /* have removed the last piece, so remove entire chunk */ (void)shmdt(sbShmBase); ret = shmctl(shm, IPC_RMID, (struct shmid_ds *)NULL); if (ret == 0) { sbShmBase = (char *)-1; shm = -1; } } if (ret == 0) { cShm--; rgsbShm[i] = (char *)-1; /* free up space */ } return(ret); } } return(-1); /* could not find this memory piece */ }