/** * @file generator.c * @date 2018-05-21 * * @brief Client program which generates solutions and submits them. */ #include "common.h" #include #include static const char *pname; static struct circ_buf *shared; static int shmfd; static sem_t *sUsedSpace; static sem_t *sFreeSpace; static sem_t *sWriteEnd; struct sigaction sa; struct AdjListNode { int dest; struct AdjListNode *next; }; struct AdjList { struct AdjListNode *head; }; struct Graph { int V; struct AdjList *array; }; static struct Graph graph; static volatile sig_atomic_t quit = 0; static void sig_handler(int signum) { quit = 1; } void usage(void) { fprintf(stderr, "SYNOPSIS\n" "\tgenerator EDGE1...\n" "EXAMPLE\n" "\tgenerator 0-1 1-2 1-3 1-4 2-4 3-6 4-3 4-5 6-0\n"); exit(EXIT_FAILURE); } struct AdjListNode *newAdjListNode(int dest) { struct AdjListNode *newNode = malloc(sizeof(struct AdjListNode)); newNode->dest = dest; newNode->next = NULL; return newNode; } void createGraph(int V) { graph.V = V; graph.array = malloc(V * sizeof(struct AdjList)); for (int i = 0; i < V; i++) graph.array[i].head = NULL; } void addEdge(int src, int dest) { struct AdjListNode *newNode = newAdjListNode(dest); newNode->next = graph.array[src].head; graph.array[src].head = newNode; } int strToInt(char *str) { char *endptr; long val; errno = 0; val = strtol(str, &endptr, 10); if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0)) { perror("[./generator] strtol"); return -2; } if (val < INT_MIN || val > INT_MAX) { fprintf(stderr, "[%s] Please choose a smaller node: ", pname); return -1; } return (int) val; } void parse(int argc, char *argv[]) { char *token; int V = 0; int src; int dest; int edges_counter = 0; int edges[(argc - 1) * 2]; for (int i = 1; i < argc; i++) { char const *edge = argv[i]; char *str, *orig_copy; str = orig_copy = strdup(edge); int count = 0; while ((token = strsep(&str, "-"))) { if (strcmp(token, edge) == 0 && str == NULL) { fprintf(stderr, "[%s] An edge consists of two " "nodes separated by a dash\n", pname); free(orig_copy); return; } if (count == 0) { src = strToInt(token); edges[edges_counter] = src; edges_counter++; if (src > V) V = src; } if (count == 1) { dest = strToInt(token); edges[edges_counter] = dest; edges_counter++; if (dest > V) V = dest; } if (count > 1) { fprintf(stderr, "[%s] An edge consists of two " "nodes separated by a dash\n", pname); free(orig_copy); return; } switch (src) { case -2: free(orig_copy); return; break; case -1: fprintf(stderr, "%s\n", edge); free(orig_copy); return; break; default: break; } count++; } free(orig_copy); } createGraph(V+1); for (int i = 0; i < (sizeof(edges) / sizeof(int)); i+=2) { addEdge(edges[i], edges[i+1]); } } void printGraph() { for (int v = 0; v < graph.V; v++) { struct AdjListNode* pCrawl = graph.array[v].head; printf("\n Adjacency list of vertex %d\n head ", v); while (pCrawl) { printf("-> %d", pCrawl->dest); pCrawl = pCrawl->next; } printf("\n"); } } void cleanup() { for (int v = 0; v < graph.V; v++) { struct AdjListNode *pCrawl = graph.array[v].head; struct AdjListNode *tmp; while (pCrawl) { tmp = pCrawl; pCrawl = pCrawl->next; free(tmp); } } free(graph.array); if (munmap(shared, sizeof(*shared)) == -1) { perror("munmap"); exit(EXIT_FAILURE); } close(shmfd); sem_close(sUsedSpace); sem_close(sFreeSpace); sem_close(sWriteEnd); } void wait_sem(sem_t *sem) { while (sem_wait(sem) == -1) { // interrupted by syscall? if (errno == EINTR) { if (quit == 1) { cleanup(); exit(EXIT_SUCCESS); } else continue; } cleanup(); exit(EXIT_FAILURE); } return; } void putSolution(int *solution) { wait_sem(sWriteEnd); if (solution[0] == -1) { wait_sem(sFreeSpace); shared->data[shared->tail] = -1; shared->tail = (shared->tail + 1) % CIRC_BUF_SIZE; wait_sem(sUsedSpace); } else { int i = 0; while (solution[i] != -1) { wait_sem(sFreeSpace); shared->data[shared->tail] = solution[i]; shared->tail = (shared->tail + 1) % CIRC_BUF_SIZE; wait_sem(sUsedSpace); i++; } } sem_post(sWriteEnd); } int findIndex(int array[], int value, int size) { int index = 0; while (index < size && array[index] != value) index++; return (index == size ? -1 : index); } void genSolution(int permutation[], int V, int *solution) { int r; // initialize array to indices for (int i = 0; i < V; i++) { permutation[i] = i; } // loop from end to start, choose random and switch // with number at current index. for (int i = (V - 1); i > 0; i--) { r = rand() % (i+1); int tmp = permutation[r]; permutation[r] = permutation[i]; permutation[i] = tmp; } int count = 0; for (int i = 0; i < MAX_ITEMS; i++) { solution[i] = -1; } for (int u = 0; u < V; u++) { int idx = findIndex(permutation, u, V); struct AdjListNode *pCrawl = graph.array[u].head; while (pCrawl) { int idx_v = findIndex(permutation, pCrawl->dest, V); if (idx > idx_v) { solution[count++] = u; solution[count++] = pCrawl->dest; if (count > MAX_ITEMS) return; break; } pCrawl = pCrawl->next; } } /* printf("["); for (int i = 0; i < (count - 1); i++) { printf("%d, ", solution[i]); } printf("%d]\n", solution[count-1]); */ } int main(int argc, char *argv[]) { if (argc == 1) usage(); pname = argv[0]; struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = &sig_handler; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); shmfd = shm_open(SHM_NAME, O_RDWR, PERMISSION); if (shmfd == -1) { perror("[./generator] shm_open"); exit(EXIT_FAILURE); } shared = mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0); if (shared == MAP_FAILED) { perror("[./generator] mmap"); exit(EXIT_FAILURE); } sFreeSpace = sem_open(SEM_FREE_SPACE, 0); sUsedSpace = sem_open(SEM_USED_SPACE, 0); sWriteEnd = sem_open(SEM_WRITE_END, 0); if (sFreeSpace == SEM_FAILED || sUsedSpace == SEM_FAILED || sWriteEnd == SEM_FAILED) { perror("[./generator] sem_open"); exit(EXIT_FAILURE); } parse(argc, argv); // seed differently for each process srand(time(NULL) * getpid()); int permutation[graph.V]; while (quit == 0) { if (shared->quit == 1) break; int solution[MAX_ITEMS]; genSolution(permutation, graph.V, solution); putSolution(solution); } cleanup(); return 0; }