Add documentation, signal handling, initial supervisor and semaphor functions
This commit is contained in:
parent
0c024698e3
commit
4d9c62cb84
@ -38,6 +38,8 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_signal();
|
||||||
|
|
||||||
/// Create a regex to check the input against
|
/// Create a regex to check the input against
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
if(regcomp(®ex, "^[0-9]*-[0-9]*$", REG_EXTENDED|REG_NOSUB)) {
|
if(regcomp(®ex, "^[0-9]*-[0-9]*$", REG_EXTENDED|REG_NOSUB)) {
|
||||||
@ -66,5 +68,10 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int buffer_shmfd = create_shmfd(BUFF_SHM_NAME);
|
||||||
|
circ_buffer = (buffer_t *)open_shm(buffer_shmfd, sizeof(buffer_t));
|
||||||
|
|
||||||
|
int wr_pos = 0;
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,25 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <semaphore.h> ///< For semaphores
|
#include <semaphore.h> ///< For semaphores
|
||||||
|
|
||||||
#define FREE_SEM_NAME "/11777707_free"
|
#define FREE_SEM_NAME "/11777707_free"
|
||||||
#define USED_SEM_NAME "/11777707_used"
|
#define USE_SEM_NAME "/11777707_used"
|
||||||
#define MUTEX_NAME "/11777707_mutex"
|
#define MUTEX_NAME "/11777707_mutex"
|
||||||
|
|
||||||
static sem_t *free_sem;
|
static sem_t *free_sem;
|
||||||
static sem_t *used_sem;
|
static sem_t *use_sem;
|
||||||
static sem_t *mutex;
|
static sem_t *mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_open(3) and does error handling.
|
||||||
|
* @details The function executes sem_open(3), giving it a semaphor name and size as parameters,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_open(3) should be expected.
|
||||||
|
* Returns a new semaphore
|
||||||
|
* @param sem_name, sem_size
|
||||||
|
* @return res
|
||||||
|
**/
|
||||||
sem_t * open_sem(char *sem_name, size_t sem_size) {
|
sem_t * open_sem(char *sem_name, size_t sem_size) {
|
||||||
sem_t *res = sem_open(sem_name, O_CREAT | O_EXCL, 0600, sem_size);
|
sem_t *res = sem_open(sem_name, O_CREAT | O_EXCL, 0600, sem_size);
|
||||||
if(res == SEM_FAILED) {
|
if(res == SEM_FAILED) {
|
||||||
@ -26,6 +35,60 @@ sem_t * open_sem(char *sem_name, size_t sem_size) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_getvalue(3) and does error handling.
|
||||||
|
* @details The function executes sem_getvalue(3), giving it a semaphor and size as parameters,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_getvalue(3) should be expected.
|
||||||
|
* Writes the value of a semaphore to a chosen pointer
|
||||||
|
* @param sem, rem
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void getval_sem(sem_t *sem, int *res) {
|
||||||
|
if(sem_getvalue(sem, res) == -1) {
|
||||||
|
fprintf(stderr, "ERROR: Failed getting semaphore value\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_wait(3) and does error handling.
|
||||||
|
* @details The function executes sem_wait(3), giving it a semaphor as a parameter,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_wait(3) should be expected.
|
||||||
|
* If the process was terminated, the function exits
|
||||||
|
* @param sem
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void wait_sem(sem_t *sem) {
|
||||||
|
if(sem_wait(sem) == -1) {
|
||||||
|
if(errno == EINTR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ERROR: Failed locking semaphore\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_post(3) and does error handling.
|
||||||
|
* @details The function executes sem_post(3), giving it a semaphor as a parameter,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_post(3) should be expected.
|
||||||
|
* @param sem
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void post_sem(sem_t *sem) {
|
||||||
|
if(sem_post(sem) == -1) {
|
||||||
|
fprintf(stderr, "ERROR: Failed unlocking semaphore\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_close(3) and does error handling.
|
||||||
|
* @details The function executes sem_close(3), giving it a semaphor as a parameter,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_close(3) should be expected.
|
||||||
|
* @param sem
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void close_sem(sem_t *sem) {
|
void close_sem(sem_t *sem) {
|
||||||
if(sem_close(sem) < 0) {
|
if(sem_close(sem) < 0) {
|
||||||
fprintf(stderr, "ERROR: Failed closing semaphore\n");
|
fprintf(stderr, "ERROR: Failed closing semaphore\n");
|
||||||
@ -33,6 +96,13 @@ void close_sem(sem_t *sem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes sem_unlink(3) and does error handling.
|
||||||
|
* @details The function executes sem_unlink(3), giving it a semaphor name as a parameter,
|
||||||
|
* and handles the errors if any. The same behaviour as sem_unlink(3) should be expected.
|
||||||
|
* @param sem_name
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void destroy_sem(char *sem_name) {
|
void destroy_sem(char *sem_name) {
|
||||||
if(sem_unlink(sem_name) < 0) {
|
if(sem_unlink(sem_name) < 0) {
|
||||||
fprintf(stderr, "ERROR: Failed closing semaphore\n");
|
fprintf(stderr, "ERROR: Failed closing semaphore\n");
|
||||||
|
@ -11,8 +11,16 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define BUFFER_SHM_NAME "/11777707_buff"
|
#define BUFF_SHM_NAME "/11777707_buff"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes shm_open(3) and does error handling.
|
||||||
|
* @details The function executes shm_open(3), giving it a name as a param,
|
||||||
|
* and handles the errors if any. The same behaviour as shm_open(3) should be expected.
|
||||||
|
* Returns a shared memory object file descriptor
|
||||||
|
* @param shm_name
|
||||||
|
* @return shmfd
|
||||||
|
**/
|
||||||
int create_shmfd(char *shm_name) {
|
int create_shmfd(char *shm_name) {
|
||||||
int shmfd = shm_open(shm_name, O_RDWR | O_CREAT, 0600);
|
int shmfd = shm_open(shm_name, O_RDWR | O_CREAT, 0600);
|
||||||
if(shmfd == -1) {
|
if(shmfd == -1) {
|
||||||
@ -22,6 +30,13 @@ int create_shmfd(char *shm_name) {
|
|||||||
return shmfd;
|
return shmfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes ftruncate(2) and does error handling.
|
||||||
|
* @details The function executes ftruncate(2), giving it a file descriptor and size as parameters,
|
||||||
|
* and handles the errors if any. The same behaviour as ftruncate(2) should be expected.
|
||||||
|
* @param shmfd, shm_size
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void truncate_shm(int shmfd, size_t shm_size) {
|
void truncate_shm(int shmfd, size_t shm_size) {
|
||||||
if(ftruncate(shmfd, shm_size) < 0) {
|
if(ftruncate(shmfd, shm_size) < 0) {
|
||||||
fprintf(stderr, "ERROR: Failed truncating shared memory object\n");
|
fprintf(stderr, "ERROR: Failed truncating shared memory object\n");
|
||||||
@ -29,6 +44,14 @@ void truncate_shm(int shmfd, size_t shm_size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes mmap(2) and does error handling.
|
||||||
|
* @details The function executes mmap(2), giving it a file descriptor and size as parameters,
|
||||||
|
* and handles the errors if any. The same behaviour as mmap(2) should be expected.
|
||||||
|
* Returns a mapped shared memory object
|
||||||
|
* @param shmfd, shm_size
|
||||||
|
* @return shm
|
||||||
|
**/
|
||||||
void* open_shm(int shmfd, size_t shm_size) {
|
void* open_shm(int shmfd, size_t shm_size) {
|
||||||
void* shm;
|
void* shm;
|
||||||
shm = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
|
shm = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
|
||||||
@ -41,10 +64,24 @@ void* open_shm(int shmfd, size_t shm_size) {
|
|||||||
return shm;
|
return shm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to write a value to shared memory object
|
||||||
|
* @details The functions copies the value of a string with a specified size to a shared memory object
|
||||||
|
* @param shm, message, message_size
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void write_to_shm(void* shm, char *message, size_t message_size) {
|
void write_to_shm(void* shm, char *message, size_t message_size) {
|
||||||
memcpy(shm, message, message_size);
|
memcpy(shm, message, message_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes munmap(2) and does error handling.
|
||||||
|
* @details The function executes munmap(2), giving it a shared memory object and size as parameters,
|
||||||
|
* and handles the errors if any. The same behaviour as munmap(2) should be expected.
|
||||||
|
* Returns a mapped shared memory object
|
||||||
|
* @param shmfd, shm_size
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void close_shm(void* shm, size_t shm_size) {
|
void close_shm(void* shm, size_t shm_size) {
|
||||||
if (munmap(shm, shm_size) == -1) {
|
if (munmap(shm, shm_size) == -1) {
|
||||||
fprintf(stderr, "ERROR: Failed unmapping shared memory object\n");
|
fprintf(stderr, "ERROR: Failed unmapping shared memory object\n");
|
||||||
@ -52,6 +89,14 @@ void close_shm(void* shm, size_t shm_size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that executes shm_unlink(3) and close(2) and does error handling.
|
||||||
|
* @details The function executes shm_unlink(3) and close(2), giving them a shared memory object name
|
||||||
|
* and a file descriptor respectively, and handles the errors if any.
|
||||||
|
* The same behaviour as shm_unlink(3) and close(2) should be expected.
|
||||||
|
* @param shm_name, shmfd
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
void destroy_shm(char *shm_name, int shmfd) {
|
void destroy_shm(char *shm_name, int shmfd) {
|
||||||
if (shm_unlink(shm_name) == -1) {
|
if (shm_unlink(shm_name) == -1) {
|
||||||
fprintf(stderr, "ERROR: Failed unlinking shared memory object\n");
|
fprintf(stderr, "ERROR: Failed unlinking shared memory object\n");
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <stdbool.h> ///< For boolean constants
|
#include <stdbool.h> ///< For boolean constants
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#define BUFF_SIZE 8
|
#define BUFF_SIZE 8
|
||||||
#define SET_MAX_SIZE 8
|
#define SET_MAX_SIZE 8
|
||||||
@ -9,15 +10,44 @@ typedef struct edge {
|
|||||||
} edge_t;
|
} edge_t;
|
||||||
|
|
||||||
/// Struct for the feedback arc set
|
/// Struct for the feedback arc set
|
||||||
typedef struct fb_set {
|
typedef struct fb_arc_set {
|
||||||
bool valid;
|
bool valid;
|
||||||
|
int edge_num;
|
||||||
edge_t edges[SET_MAX_SIZE];
|
edge_t edges[SET_MAX_SIZE];
|
||||||
} fb_set_t;
|
} fb_arc_set_t;
|
||||||
|
|
||||||
/// Struct for the circular buffer
|
/// Struct for the circular buffer
|
||||||
typedef struct buffer {
|
typedef struct buffer {
|
||||||
bool terminate;
|
bool finished;
|
||||||
fb_set_t sets[BUFF_SIZE];
|
short best_arc_len;
|
||||||
|
fb_arc_set_t sets[BUFF_SIZE];
|
||||||
} buffer_t;
|
} buffer_t;
|
||||||
|
|
||||||
|
static bool terminate = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to execute when the program gets a signal
|
||||||
|
* @details flips the terminate variable to true
|
||||||
|
* @param none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
static void signal_handler() {
|
||||||
|
terminate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to process the signals passed by the user
|
||||||
|
* @details creates a new sigaction structure
|
||||||
|
* and changes the behaviour of the SIGINT and SIGTERM signals
|
||||||
|
* @param none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
static void process_signal(void){
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = signal_handler;
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static buffer_t *circ_buffer;
|
static buffer_t *circ_buffer;
|
||||||
|
@ -31,27 +31,70 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_signal();
|
||||||
|
|
||||||
/// Open shared memory objects
|
/// Open shared memory objects
|
||||||
int buffer_shmfd = create_shmfd(BUFFER_SHM_NAME);
|
int buffer_shmfd = create_shmfd(BUFF_SHM_NAME);
|
||||||
truncate_shm(buffer_shmfd, BUFF_SIZE);
|
truncate_shm(buffer_shmfd, BUFF_SIZE);
|
||||||
circ_buffer = (buffer_t *)open_shm(buffer_shmfd, sizeof(buffer_t));
|
circ_buffer = (buffer_t *)open_shm(buffer_shmfd, sizeof(buffer_t));
|
||||||
|
|
||||||
/// Open semaphores
|
/// Open semaphores
|
||||||
free_sem = open_sem(FREE_SEM_NAME, BUFF_SIZE);
|
free_sem = open_sem(FREE_SEM_NAME, BUFF_SIZE);
|
||||||
used_sem = open_sem(USED_SEM_NAME, 0);
|
use_sem = open_sem(USE_SEM_NAME, 0);
|
||||||
mutex = open_sem(MUTEX_NAME, 1);
|
|
||||||
|
|
||||||
|
int free_space = 0;
|
||||||
|
int use_space = 0;
|
||||||
|
int r_pos = 0; ///< Position of the circular buffer to read from
|
||||||
|
circ_buffer->best_arc_len = __INT8_MAX__;
|
||||||
|
|
||||||
|
fb_arc_set_t fb_arc;
|
||||||
|
while(terminate == false) {
|
||||||
|
/// Get the values of the semaphores
|
||||||
|
getval_sem(free_sem, &free_space);
|
||||||
|
getval_sem(use_sem, &use_space);
|
||||||
|
|
||||||
|
wait_sem(use_sem);
|
||||||
|
|
||||||
|
/// Loop until we find a place that has been written to
|
||||||
|
while(circ_buffer->sets[r_pos].valid == false) {
|
||||||
|
r_pos = (r_pos + 1) % BUFF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the valid set and save it
|
||||||
|
fb_arc = circ_buffer->sets[r_pos];
|
||||||
|
circ_buffer->sets[r_pos].valid = false;
|
||||||
|
|
||||||
|
post_sem(free_sem); ///< Free the semaphore
|
||||||
|
|
||||||
|
r_pos = (r_pos + 1) % BUFF_SIZE; ///< Increase read position
|
||||||
|
|
||||||
|
if(fb_arc.edge_num == 0) {
|
||||||
|
/// If the graph is acyclic, set the terminate flag
|
||||||
|
puts("The graph is acyclic!");
|
||||||
|
signal_handler();
|
||||||
|
} else if(fb_arc.edge_num < circ_buffer->best_arc_len) {
|
||||||
|
/// Save ther best feedback arc length and print a solution
|
||||||
|
circ_buffer->best_arc_len = fb_arc.edge_num;
|
||||||
|
printf("Solution with %d edges: ", circ_buffer->best_arc_len);
|
||||||
|
|
||||||
|
for(int i=0; i < fb_arc.edge_num; i++) {
|
||||||
|
printf("%d-%d ", fb_arc.edges[i].u, fb_arc.edges[i].v);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Close and destory semaphores
|
/// Close and destory semaphores
|
||||||
close_sem(free_sem);
|
close_sem(free_sem);
|
||||||
close_sem(used_sem);
|
close_sem(use_sem);
|
||||||
close_sem(mutex);
|
close_sem(mutex);
|
||||||
|
|
||||||
destroy_sem(FREE_SEM_NAME);
|
destroy_sem(FREE_SEM_NAME);
|
||||||
destroy_sem(USED_SEM_NAME);
|
destroy_sem(USE_SEM_NAME);
|
||||||
destroy_sem(MUTEX_NAME);
|
destroy_sem(MUTEX_NAME);
|
||||||
|
|
||||||
/// Close and destroy shared memory objects
|
/// Close and destroy shared memory objects
|
||||||
close_shm(circ_buffer, sizeof(buffer_t));
|
close_shm(circ_buffer, sizeof(buffer_t));
|
||||||
destroy_shm(BUFFER_SHM_NAME, buffer_shmfd);
|
destroy_shm(BUFF_SHM_NAME, buffer_shmfd);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user