Sie befinden sich hier: Termine » Prüfungsfragen und Altklausuren » Prüfungen im Bachelor-Studium (1. - 5. Semester) » Lösungsvorschlag   (Übersicht)

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 <dirent.h>
#include <errno.h> 
#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/stat.h>
 
// 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;
}