====== Lösungsvorschlag ====== Restliche Aufgabenlösungen siehe Pad: https://pad.stuve.fau.de/p/sp%3eaud ==== Aufgabe 2: ==== **a)** /* Klausur Februar 2014 - Aufgabe 2: mops */ #include #include #include #include #include #include #include #include #include // weitere Includes, Konstanten // globale Variablen, Funktionsdeklarationen usw. #define BUFFER_SIZE 64 unsigned int spawnThreads(void); void *feedPrinter(const char*); SEM *semCreate(int); void P(SEM *); void V(SEM *); struct SEM { volatile int val; pthread_mutex_t m; pthread_cond_t c; }; static int port; static int buffer[BUFFER_SIZE]; static int in, out; static SEM *inSem, *outSem; static void die(const char message[]) { perror(message); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { unsigned int printer; int sock; struct sockaddr_in6 addr; if (argv != 2) { fprintf(stderr, "usage: ./mops port\n"); return 0; } if ((inSem = semCreate(BUFFER_SIZE)) == NULL) die("semCreate"); if ((outSem = semCreate(0)) == NULL) die("semCreate"); port = (int) strtol(argv[1]); printer = spawnThreads(); if (printer < 0) die("spawnThreads"); printf("%d printer devices found", printer); if (printer == 0) return 0; sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0) die("socket"); addr = { .sin6_family = AF_INET6, .sin6_port = htons(port), .sin6_addr = in6addr_any, }; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) != 0) die("bind"); if (listen(sock, SOMAXCONN) != 0) die("bind"); for (;;) { int clientSock = accept(sock, NULL, NULL); if (clientSock < 0) continue; P(inSem); buffer[in] = clientSock; in = (in + 1) % BUFFER_SIZE V(outSem); } close(sock); return 0; } unsigned int spawnThreads() { unsigned int numb; DIR *dir = opendir("/dev"); if (dir == NULL) return numb; struct dirent *ent; while (errno = 0, (ent = readdir(dir)) != NULL) { if (ent->d_name[0] == 'l' && ent->d_name[1] == 'p') { char path[6 + strlen(ent->d_name)]; snprintf(path, "/dev/%s", ent->d_name); struct stat s; if (lstat(path, &s) < 0) return 0; if (S_ISREG(s.st_mode)) { if (pthread_create(NULL, NULL, feedPrinter, &ent->d_name) < 0) return 0; numb++; } } } if (errno != 0) return 0; return numb; } void *feedPrinter(const char device[]) { FILE *dev = fopen(device, "a"); if (dev == NULL) { return; } for (;;) { int sock; P(outSem); do { sock = buffer[out]; out = (out + 1) % BUFFER_SIZE; } while (__sync_compare_and_swap(buffer[out], sock, -1) == false); V(inSem); FILE *req; if ((req = fdopen(sock, "r")) == NULL) continue; int c; while ((c = fgetc(req)) != EOF) fputc(c, dev); close(sock); } } SEM *semCreate(int initial_value) { struct SEM sem = { .val = initial_value } errno = 0; if ((errno = pthread_mutex_init(sem.m, NULL)) != 0) return NULL; if ((errno = pthread_cond_init(sem.c, NULL)) != 0) return NULL; return &sem; } void P(SEM *sem) { if ((errno = pthread_mutex_lock(&sem->m)) != 0) return; while (sem->val <= 0) { if ((errno = pthread_cond_wait(&sem->c)) != 0) { pthread_mutex_unlock(&sem->m); return; } } sem->val-- if ((errno = pthread_mutex_unlock(&sem->m)) != 0) return; } void V(SEM *sem) { if ((errno = pthread_mutex_lock(&sem->m)) != 0) return; sem->val++ if ((errno = pthread_cond_broadcast(&sem->c)) != 0) return; if ((errno = pthread_mutex_unlock(&sem->m)) != 0) return; }