diff --git a/.gitignore b/.gitignore index 620cfea..bd8f4d2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ http/client http/server mygrep/mygrep cpair/cpair +fb_arc_set/supervisor +fb_arc_set/generator diff --git a/fb_arc_set/Makefile b/fb_arc_set/Makefile index 1624de4..a7a0f9e 100644 --- a/fb_arc_set/Makefile +++ b/fb_arc_set/Makefile @@ -5,16 +5,16 @@ TARGET_2 = supervisor all: $(TARGET_1).c $(TARGET_2).c $(CC) $(CFLAGS) $(TARGET_1).c $(TARGET_2).c - $(CC) $(TARGET_1).o -o $(TARGET_1) - $(CC) $(TARGET_2).o -o $(TARGET_2) + $(CC) $(TARGET_1).o -o $(TARGET_1) -lrt + $(CC) $(TARGET_2).o -o $(TARGET_2) -lrt generator: $(TARGET_1).c $(CC) $(CFLAGS) $(TARGET_1).c - $(CC) $(TARGET_1).o -o $(TARGET_1) + $(CC) $(TARGET_1).o -o $(TARGET_1) -lrt supervisor: $(TARGET_2).c $(CC) $(CFLAGS) $(TARGET_2).c - $(CC) $(TARGET_2).o -o $(TARGET_2) + $(CC) $(TARGET_2).o -o $(TARGET_2) -lrt install: cp $(TARGET_1) /usr/local/bin/graph-$(TARGET_1) diff --git a/fb_arc_set/generator.c b/fb_arc_set/generator.c index e69de29..0eb9e4f 100644 --- a/fb_arc_set/generator.c +++ b/fb_arc_set/generator.c @@ -0,0 +1,44 @@ +/** + * @file generator.c + * @author Ivaylo Ivanov 11777707 + * @date 11.01.2018 + * + * @brief Generator program module. + * + * The generator program takes a graph as input. The program repeatedly generates a random solution + * to the problem as described on the first page and writes its result to the circular buffer. It repeats this + * procedure until it is notified by the supervisor to terminate. + * The generator program takes as arguments the set of edges of the graph. + * Each positional argument is one edge; at least one edge must be given. An edge is specified by a string, + * with the indices of the two nodes it connects separated by a -. Since the graph is directed, the edge starts + * at the first node and leads to the second node. Note that the number of nodes of the graph is implicitly + * provided through the indices in the edges. In the example above the generator program is called with + * the graph shown on the first page. + * The generator uses the algorithm described on the first page to generate random feedback arc sets for the + * given graph. It writes these feedback arc sets to the circular buffer, one at a time; therefore a feedback + * arc set is a single element of the circular buffer. The generator may produce debug output, describing + * the feedback arc sets which it writes to the circular buffer. + * + * SYNOPSIS + * generator EDGE1 EDGE2 ... + * + * EXAMPLE + * generator 0-1 1-2 1-3 1-4 2-4 3-6 4-3 4-5 6-0 + * + **/ +#include "shared/shm.c" + +int main(int argc, char *argv[]) { + if(argc > 1) { + fprintf(stderr, "ERROR: Command takes no arguments"); + exit(EXIT_FAILURE); + } + + void* terminate_shm = open_shm(TERMINATE_SHM, TERMINATE_SHM_SIZE); + + write_to_shm(terminate_shm, "1", TERMINATE_SHM_SIZE); + puts(terminate_shm); + close_shm(terminate_shm, TERMINATE_SHM_SIZE); + destroy_shm(TERMINATE_SHM); +} + diff --git a/fb_arc_set/shared/shm.c b/fb_arc_set/shared/shm.c new file mode 100644 index 0000000..6a8e49a --- /dev/null +++ b/fb_arc_set/shared/shm.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define TERMINATE_SHM "/terminate" +#define TERMINATE_SHM_SIZE 8 + +void* open_shm(char *shm_name, size_t shm_size) { + int shmfd = shm_open(shm_name, O_RDWR | O_CREAT, 0600); + if(shmfd == -1) { + fprintf(stderr, "ERROR: Failed creating shared memory object"); + exit(EXIT_FAILURE); + } + + if(ftruncate(shmfd, shm_size) < 0) { + fprintf(stderr, "ERROR: Failed truncating shared memory object"); + exit(EXIT_FAILURE); + } + + void* shm; + shm = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0); + + if(shm == MAP_FAILED) { + fprintf(stderr, "ERROR: Failed mapping shared memory object"); + exit(EXIT_FAILURE); + } + + return shm; +} + +void write_to_shm(void* shm, char *message, size_t message_size) { + memcpy(shm, message, message_size); +} + +void close_shm(void* shm, size_t shm_size) { + if (munmap(shm, shm_size) == -1) { + fprintf(stderr, "ERROR: Failed unmapping shared memory object"); + exit(EXIT_FAILURE); + } +} + +void destroy_shm(char *shm_name) { + if (shm_unlink(shm_name) == -1) { + fprintf(stderr, "ERROR: Failed unlinking shared memory object"); + exit(EXIT_FAILURE); + } +} diff --git a/fb_arc_set/supervisor.c b/fb_arc_set/supervisor.c index e69de29..7f25a77 100644 --- a/fb_arc_set/supervisor.c +++ b/fb_arc_set/supervisor.c @@ -0,0 +1,37 @@ +/** + * @file supervisor.c + * @author Ivaylo Ivanov 11777707 + * @date 11.01.2018 + * + * @brief Supervisor program module. + * + * The supervisor sets up the shared memory and the semaphores and initializes the circular buffer required + * for the communication with the generators. It then waits for the generators to write solutions to the + * circular buffer. + * The supervisor program takes no arguments. + * Once initialization is complete, the supervisor reads the solutions from the circular buffer and remembers the best solution so far, i.e. the solution with the least edges. Every time a better solution than the + * previous best solution is found, the supervisor writes the new solution to standard output. If a generator + * writes a solution with 0 edges to the circular buffer, then the graph is acyclic and the supervisor terminates. Otherwise the supervisor keeps reading results from the circular buffer until it receives a SIGINT + * or a SIGTERM signal. + * Before terminating, the supervisor notifies all generators that they should terminate as well. This can + * be done by setting a variable in the shared memory, which is checked by the generator processes before + * writing to the buffer. The supervisor then unlinks all shared resources and exits. + * + * SYNOPSIS + * supervisor + * + **/ +#include "shared/shm.c" + +int main(int argc, char *argv[]) { + if(argc > 1) { + fprintf(stderr, "ERROR: Command takes no arguments"); + exit(EXIT_FAILURE); + } + + void* terminate_shm = open_shm(TERMINATE_SHM, TERMINATE_SHM_SIZE); + + write_to_shm(terminate_shm, "1", TERMINATE_SHM_SIZE); + close_shm(terminate_shm, TERMINATE_SHM_SIZE); + destroy_shm(TERMINATE_SHM); +}