From eb852388280db611c26e64d779073edaaadb724c Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 5 Jun 2016 22:15:12 +0200 Subject: [PATCH] locks: using fcntl --- locks/Makefile | 6 +- locks/fcntllocks.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++++++++ locks/fcntllocks.h | 37 ++++++ 3 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 locks/fcntllocks.c create mode 100644 locks/fcntllocks.h diff --git a/locks/Makefile b/locks/Makefile index 9a14c0d..75f0de5 100644 --- a/locks/Makefile +++ b/locks/Makefile @@ -1,7 +1,11 @@ -all: flocks +all: flocks fcntllocks flocks: flocks.c gcc -Wall -g -o flocks flocks.c -lpthread +fcntllocks: fcntllocks.c + gcc -Wall -g -o fcntllocks fcntllocks.c -lpthread + clean: rm -f flocks + rm -f fcntllocks diff --git a/locks/fcntllocks.c b/locks/fcntllocks.c new file mode 100644 index 0000000..3308264 --- /dev/null +++ b/locks/fcntllocks.c @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fcntllocks.h" + + + +pthread_mutex_t gateMutex; +pthread_cond_t gateBroadCast; +bool isGateOpen = false; +int threadsNumber = 20; + + +struct sigaction sigintAction; /*Stores the init SIGINT sigaction value*/ +char *fileName = "/tmp/locks"; + + + + + + +int main (int argc, char *argv[]) +{ + int c; /*Getopt parameter*/ + /*Default values*/ + struct sigaction sa; /*sig actions values*/ + + opterr = 0; + while ((c = getopt (argc, argv, "p:t:f:")) != -1) { + switch (c) { + case 'p': + fileName = optarg; + break; + case 't': + threadsNumber = atoi(optarg); + break; + case '?': + if ((optopt == 'p') || (optopt == 't') || (optopt == 'f')) + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Invalid option '-%c'.\n", optopt); + else + fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); + return -1; + default: + abort (); + } + } + + /*This program does not admit options*/ + if (optind < argc) { + fprintf (stderr, "This program does not admit options just argument elements with their values.\n"); + return -1; + } + + + /* If running from console, user may finish this process using SIGINT (Ctrl-C)*/ + /* Check to make sure that the shell has not set up an initial action of SIG_IGN before I establish my own signal handler. + * As seen on http://www.gnu.org/software/libc/manual/html_node/Initial-Signal-Actions.html#Initial-Signal-Actions + */ + memset (&sa, 0, sizeof(sa)); + memset (&sigintAction, 0, sizeof(sigaction)); + if (sigaction (SIGINT, NULL, &sa) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT retrieve current signal handler failed:", strerror(errno)); + + return -1; + } + + if (sa.sa_handler != SIG_IGN) { + /* Save the current SIGINT sigaction value. We use it to restore SIGINT handler in my custom SIGINT handler.*/ + memcpy (&sigintAction, &sa, sizeof(sigaction)); + + sa.sa_handler = &sigint_handler; + sa.sa_flags = SA_RESTART; + if (sigemptyset(&sa.sa_mask) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT empty mask", strerror(errno)); + + return -1; + } + if (sigaction(SIGINT, &sa, NULL) < 0) { + fprintf (stderr, "%s: %s\n", "SIGINT set signal handler failed", strerror(errno)); + + return -1; + } + } + + if (threadsNumber > 0) { + return test_threads_concurrency(); + } else { + return test_require_user(); + } + + return 0; +} + +int test_threads_concurrency() +{ + int returnValue = 0; + int createIndex; + int joinIndex; + pthread_t threadIds [threadsNumber]; /*Threads identifier numbers*/ + + pthread_mutex_init(&gateMutex, NULL); + pthread_cond_init(&gateBroadCast, NULL); + closeGate(); + + + for (createIndex = 0; createIndex < threadsNumber; createIndex++) { + print_with_date (stdout, "Thread %d created\n", createIndex); + if (pthread_create (&threadIds[createIndex], NULL, &thread_lock, (void *) createIndex) != 0 ) { + print_with_date (stderr, "Thread %d creation failed\n", createIndex, strerror(errno)); + returnValue = -1; + break; + } + } + + sleep(5); + openGate(); + + for (joinIndex = createIndex; joinIndex --> 0; ) { + if (pthread_join(threadIds[joinIndex], NULL) != 0) { + print_with_date (stderr, "Thread %d join error\n", joinIndex, strerror(errno)); + returnValue = -1; + } + } + + return returnValue; +} + +void *thread_lock(void * arg) +{ + struct flock fl; + int threadNumber; + int fd; + int flockErr; + + threadNumber = (int) arg; + + + fd = open(fileName, O_CREAT | O_RDWR, 0664); + if (fd == -1) { + goto end; + print_with_date (stderr, "Thread %d, open file error", threadNumber, strerror(errno)); + } + + + gate(); + + + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + print_with_date (stdout, "Thread %d: before lock\n", threadNumber); + do { + flockErr = fcntl(fd, F_SETLKW, &fl); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date (stderr, "Thread %d: F_WRLCK/F_SETLKW, exclusive lock error", threadNumber, strerror(errno)); + goto end; + } + print_with_date (stdout, "Thread %d: after lock\n", threadNumber); + + + sleep(5); + + + print_with_date(stdout, "Thread %d: before release lock\n", threadNumber); + fl.l_type = F_UNLCK; + do { + fcntl(fd, F_SETLK, &fl); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date(stderr, "Thread %d: F_UNLCK unlock error", threadNumber, strerror(errno)); + goto end; + } + print_with_date(stdout, "Thread %d: after release lock\n", threadNumber); + + +end: + close (fd); + pthread_exit(0); +} + +int test_require_user() { + struct flock fl; + int returnValue = -1; + int fd; + int flockErr; + + + fd = open(fileName, O_CREAT | O_RDWR, 0664); + if (fd == -1) { + print_with_date(stderr, "Open file error", strerror(errno)); + goto end; + } + + + fprintf(stdout, "Press ENTER key for locking file: %s\n", fileName); + fflush(stdout); + getchar(); + + + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + print_with_date (stdout, "Before lock\n"); + do { + flockErr = fcntl(fd, F_SETLKW, &fl); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date (stderr, "F_WRLCK/F_SETLKW, exclusive lock error", strerror(errno)); + goto end; + } + print_with_date (stdout, "After lock\n"); + + + fprintf(stdout, "Press ENTER key for unlocking file: %s\n", fileName); + fflush(stdout); + getchar(); + + + print_with_date(stdout, "Before release lock\n"); + fl.l_type = F_UNLCK; + do { + fcntl(fd, F_SETLK, &fl); + } while(flockErr == -1 && errno == EINTR); + + if (flockErr == -1) { + print_with_date(stderr, "F_UNLCK unlock error", strerror(errno)); + goto end; + } + print_with_date(stdout, "After release lock\n"); + + + returnValue = 0; +end: + close (fd); + return returnValue; +} + +int print_with_date(FILE *stream, const char *format, ...) { + va_list arg; + int done; + time_t rawtime; + char buff[100]; + char msg[50]; + char dateformatter[100] = "%s: "; + struct tm timeinfo; + + time ( &rawtime); + localtime_r ( &rawtime, &timeinfo); + strftime(buff, 50, "%Y-%m-%d %H:%M:%S", &timeinfo); + + va_start (arg, format); + vsnprintf (msg , 50, format, arg); + + strcat(dateformatter, msg); + done = fprintf (stream, dateformatter, buff, msg); + va_end (arg); + + if (done < 0) { + fflush (stream); + return done; + } else { + done = fflush (stream); + return done; + } +} + +void gate() { + + pthread_mutex_lock(&gateMutex); + + while(!isGateOpen) { + pthread_cond_wait(&gateBroadCast, &gateMutex); + } + + pthread_mutex_unlock(&gateMutex); +} + +void openGate() { + pthread_mutex_lock(&gateMutex); + + isGateOpen = true; + pthread_cond_broadcast(&gateBroadCast); + + pthread_mutex_unlock(&gateMutex); +} + +void closeGate() { + pthread_mutex_lock(&gateMutex); + + isGateOpen = false; + + pthread_mutex_unlock(&gateMutex); +} + +void sigint_handler(int sig) +{ + if (sigaction(SIGINT, &sigintAction, NULL) < 0) { + exit (EXIT_FAILURE); + } + kill(getpid(), SIGINT); +} + + diff --git a/locks/fcntllocks.h b/locks/fcntllocks.h new file mode 100644 index 0000000..7535209 --- /dev/null +++ b/locks/fcntllocks.h @@ -0,0 +1,37 @@ + + + +void gate(); + +void openGate(); + +void closeGate(); + +int print_with_date(FILE *stream, const char *format, ...); + +/****************************************************************************************/ +/* This method is used by pthread_create */ +/* */ +/* INPUT PARAMETER: socket file descriptor */ +/* RETURNS: void */ +/****************************************************************************************/ +void *thread_lock(void *arg); + + +int test_threads_concurrency(); + +int test_require_user(); + + + + +/****************************************************************************************/ +/* This method is used by pthread_create */ +/* */ +/* INPUT PARAMETER: socket file descriptor */ +/* RETURNS: void */ +/****************************************************************************************/ +void sigint_handler(); + + + -- 2.1.4