lecture 11 -- Unix semaphore APIs * review of basic semaphore operation: P/down... if semaphore value is 0, block/sleep and register self as sleeper otherwise, decrement semaphore value V/up.... if any sleepers, wake one (Dijkstra: random; Unix: oldest) otherwise, increment semaphore value * to create a semaphore in Unix: - reserve storage for an integer - if semaphore is to be shared among >1 proc, put that integer in a shared memory segment - use semget(), providing a key, permissions, and # of sems in group - use semctl() to initialize value (using val field in semun union) - use semop() to perform up/down operations * demo of creating a semaphore and then multiple procs using it (see code below) * discussion of assn4 producer/consumer problem: - how does it deadlock? (example -- producer has a plain donut, so it is determined to insert into plain donut ring, but plain donut ring is full, so producer blocks. if all consumers are blocked trying to eat donuts from other rings that then are empty, everyone's blocked --> DEADLOCK.) - how can detect deadlock? ideas: + 5 or 30 sec elapse with no activity (how long should you wait?) + all 5 procs (1 producer + 4 consumers) are all simultaneously blocked. BUT: this won't do it. even if all 4 ring buffer semaphores are 0, it could mean that 4 procs are in their critical region and the 5th proc is waiting for one of them to finish (e.g., producer is inserting a plain donut and 3 consumers are eating from 3 other donuts, 1 consumer is blocked, and a moment later, the producer+ 3consumers will finish and everything is OK). need to know diff between semaphore being 0 (which might mean that critical access is making progress) and semaphore being 0 and no chance of progress (e.g., producer blocked and buffer is full). ------------------------------ SEMCREATE.C ------------------------------ #include #include #include #include #include #define SHMKEY (key_t)10398 #define SEMKEY (key_t)1033 union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ } sem_union; int main () { int shmid; int rc; int *semaphore; struct sembuf sem_op; unsigned short int getarray[1]; shmid = shmget (SHMKEY, sizeof(int), IPC_CREAT | 0600); if (shmid == -1) { perror("shared get failed: "); exit(1); } printf("shmget is happy\n"); printf ("created shared mem with ID = %d\n", shmid); semaphore = (int *) shmat(shmid, (const void *)0, 0); if (semaphore == (int *) -1 ) { perror("shared attach failed: "); exit(1); } printf ("attached shared mem\n"); *semaphore = semget(SEMKEY, 1, IPC_CREAT | 0600); if (*semaphore == -1) { perror("semget failed\n"); exit(1); } printf("semget OK\n"); sem_union.val= 1; rc = semctl(*semaphore, 0, SETVAL, sem_union); if (rc == -1) { perror("semctl failed on SETVAL\n"); exit(1); } printf("semaphore set to 1\n"); // creation is done, we could stop here /* P operation on the semaphore (DOWN) */ sem_op.sem_num = 0; sem_op.sem_op = -1; sem_op.sem_flg = 0; semop(*semaphore, &sem_op, 1); printf("got control of the semaphore\n"); printf("privileged access ... I RULE!!!!!\n"); sem_union.array = getarray; rc = semctl(*semaphore, 0, GETALL, sem_union); if (rc == -1) { perror("semctl failed on GETALL\n"); exit(1); } printf("semaphore value is now %d\n", getarray[0]); /* V operation on semaphore (UP) */ sem_op.sem_num = 0; sem_op.sem_op = 1; sem_op.sem_flg = 0; semop(*semaphore, &sem_op, 1); printf("OK I'm done\n"); rc = semctl(*semaphore, 0, GETALL, sem_union); if (rc == -1) { perror("semctl failed on GETALL\n"); exit(1); } printf("semaphore value is now %d\n", getarray[0]); } ------------------------------ SEMUSE.C ------------------------------ #include #include #include #include #include #include #include #define SHMKEY (key_t)10398 #define SEMKEY (key_t)1033 union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ } sem_union; int main () { int shmid; int rc; int *semaphore; struct sembuf sem_op; int i,j; shmid = shmget (SHMKEY, sizeof(int), 0600); if (shmid == -1) { perror("shared get failed: "); exit(1); } printf("shmget is happy\n"); printf ("found shared mem with ID = %d\n", shmid); semaphore = (int *) shmat(shmid, (const void *)0, 0); if (semaphore == (int *) -1 ) { perror("shared attach failed: "); exit(1); } printf ("attached shared mem\n"); *semaphore = semget(SEMKEY, 1, 0600); if (*semaphore == -1) { perror("semget failed\n"); exit(1); } printf("semget OK -- got the existing semaphore\n"); while (1) { printf("about to wait on the semaphore!\n"); fflush(stdout); /* P operation on the semaphore (DOWN) */ sem_op.sem_num = 0; sem_op.sem_op = -1; sem_op.sem_flg = 0; semop(*semaphore, &sem_op, 1); printf("got control of the semaphore\n"); j=1+(int) (5.0*rand()/(RAND_MAX+1.0)); printf("privileged access ... I WILL RULE FOR %d SECONDS!!!!!\n", j); for (i=j; i>0; i--) { printf("%d...", i); fflush(stdout); sleep(1); } /* V operation on semaphore (UP) */ sem_op.sem_num = 0; sem_op.sem_op = 1; sem_op.sem_flg = 0; semop(*semaphore, &sem_op, 1); printf("OK I'm done\n"); } }