int client(void) { int s; /* spingrab in order to avoid sleep, testcase has a timeout */ while ( (s = msemgrab(SEM0, 0)) == -1 ); int cnt = 0; for (int i = 0; i < 5; ++i) { if (msemdown(s, 1, 1) != 0) { if (errno == EINTR) { /* interrupted by syscall, try again */ continue; } perror("mP(1)"); break; } printf("c%d", cnt); cnt += 2; fflush(stdout); if (msemup(s, 1, 0) != 0) { perror("mV(0)"); break; } } return 0; }
/** * Write buffer to shared memory * * @param data buffer to write to shared memory * * @return -1 on error, 0 otherwise */ static int ipc_write(char *data) { int ret = -1; /* It makes no sense to proceed if nobody is listening */ ipc_require_listener(); /* * Firts wait for write queue to let us in * if cnd or mt are no valid semaphores anymore, another process has already removed them. so we will simply return -1 */ if(msemdown(cnd, 1, 0) != -1) { /* While we are in the mutual exclusive section, we don't listen to signals, because it would be hard to reset the state of the mutex */ sigset_t blocked_signals, curr_set; (void) sigfillset(&blocked_signals); (void) sigprocmask(SIG_BLOCK, &blocked_signals, &curr_set); /* Mutual exclusive section so no other process removes shm segment meanwhile */ if(semdown(mtx) != -1) { if(data == NULL) { /* Signal EOF to Listener */ shared->flag |= EOF_F; } else { for(int i = 0; i <= MAX_BUF_SIZE; ++i) { shared->data[i] = data[i]; /* Null char */ if(data[i] == 0) { break; } } } ret = (semup(mtx) == -1 ? -1 : 0); } /* Reset to original procmask*/ (void) sigprocmask(SIG_SETMASK, &curr_set, NULL); /* Signal read queue to proceed */ ret = (msemup(cnd, 1, 1) == -1 ? -1 : 0); } return ret; }
/** * Read shared data and calculate statistics * * @return -1 on error, 0 on EOF, number of read chars otherwise */ static int ipc_process(void) { int i = -1; /* * First, wait for read queue to let us in * if cnd or mt are no valid semaphores anymore, another process has already removed them. so we will simply return -1 */ if(msemdown(cnd, 1, 1) != -1) { /* While we are in the mutual exclusive section, we don't listen to signals, because it would be hard to reset the state of the mutex */ sigset_t blocked_signals, curr_set; (void) sigfillset(&blocked_signals); (void) sigprocmask(SIG_BLOCK, &blocked_signals, &curr_set); /* Mutual exclusive section so no other process removes shm segment meanwhile */ if(semdown(mtx) != -1) { i = 0; /* EOF Flag has been set, return 0 */ if((shared->flag & EOF_F) != 1) { for(i = 0; i <= MAX_BUF_SIZE; ++i) { int c; /* Null character */ if(shared->data[i] == 0) { break; } /* We will only distinguish between uppercase'd chars */ c = toupper(shared->data[i]) - ASCII_CHAR_OFFSET; if(c < 0 || c > ASCII_CHAR_MAX) { /* No Ascii Letter -> inc 'others' counter */ shared->stat[ASCII_CHAR_MAX + 1]++; } else { /* inc letter counter */ shared->stat[c]++; } /* Total number of characters */ shared->total++; /* Clear out buffer */ shared->data[i] = 0; } } if(semup(mtx) == -1) { i = -1; } } /* Reset to original procmask*/ (void) sigprocmask(SIG_SETMASK, &curr_set, NULL); /* Let write queue proceed */ if(msemup(cnd, 1, 0) == -1) { i = -1; } } return i; }