[Devel] [PATCH][cr-tests] pthread4: Ensure mutexes are consistent across C/R
Sukadev Bhattiprolu
sukadev at linux.vnet.ibm.com
Fri Jan 8 17:31:30 PST 2010
From: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
Date: Fri, 8 Jan 2010 10:56:38 -0800
Subject: [PATCH] pthread4: Ensure mutexes are consistent across C/R
Pthread mutex (not) held at checkpoint must continue to be (not) held
after restart.
Signed-off-by: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
---
process-tree/Makefile | 2 +-
process-tree/pthread4.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 286 insertions(+), 1 deletions(-)
create mode 100644 process-tree/pthread4.c
diff --git a/process-tree/Makefile b/process-tree/Makefile
index b043394..64fdd20 100644
--- a/process-tree/Makefile
+++ b/process-tree/Makefile
@@ -1,5 +1,5 @@
-targets = ptree1 pthread1 pthread2 pthread3
+targets = ptree1 pthread1 pthread2 pthread3 pthread4
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
diff --git a/process-tree/pthread4.c b/process-tree/pthread4.c
new file mode 100644
index 0000000..b7afcab
--- /dev/null
+++ b/process-tree/pthread4.c
@@ -0,0 +1,285 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <wait.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libcrtest.h>
+#define __USE_UNIX98
+#include <pthread.h>
+
+
+#define ERROR_EXIT ((void *)1)
+#define MIN_STACK_SIZE (64 *1024)
+#define LOG_PREFIX "logs.d/pthread4"
+
+FILE *logfp;
+int num_threads = 4;
+int *tstatus;
+pthread_barrier_t cr_ready;
+pthread_barrier_t threads_created;
+pthread_mutex_t mutex;
+
+static void usage(char *argv[])
+{
+ printf("%s [h] [-n num-threads]\n", argv[0]);
+ printf("\t <num-threads> # of threads, default 5\n");
+ do_exit(1);
+}
+
+void * do_work(void *arg)
+{
+ int tnum = (int)arg;
+ int rc;
+ int lock_acquired;
+
+ /*
+ * Wait for all threads to be created, so a random thread can
+ * get the lock.
+ */
+ rc = pthread_barrier_wait(&threads_created);
+ if (rc != PTHREAD_BARRIER_SERIAL_THREAD && rc != 0) {
+ fprintf(logfp, "%d: pthread_barrier_wait() failed, rc %d, "
+ "error %s\n", tnum, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ rc = pthread_mutex_trylock(&mutex);
+ if (rc && rc != EBUSY) {
+ fprintf(logfp, "%d: pthread_mutex_trylock() failed, rc %d, "
+ "error %s\n", tnum, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ lock_acquired = 0;
+ if (!rc)
+ lock_acquired++;
+
+ fprintf(logfp, "%d: Thread %lu: lock_acquired %d waiting for "
+ "checkpoint\n", tnum, pthread_self(), lock_acquired);
+ fflush(logfp);
+
+ /*
+ * Inform main-thread we are ready for checkpoint.
+ */
+ rc = pthread_barrier_wait(&cr_ready);
+ if (rc != PTHREAD_BARRIER_SERIAL_THREAD && rc != 0) {
+ fprintf(logfp, "%d: pthread_barrier_wait() failed, rc %d, "
+ "error %s\n", tnum, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * Wait for checkpoint/restart.
+ */
+ while(!test_done())
+ sleep(1);
+
+ rc = pthread_mutex_trylock(&mutex);
+ if (rc && rc != EBUSY) {
+ fprintf(logfp, "%d: pthread_mutex_trylock() failed, rc %d, "
+ "error %s\n", tnum, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * If I already hold the lock, this trylock better fail :-)
+ */
+ tstatus[tnum] = 0;
+ if (lock_acquired && !rc) {
+ fprintf(logfp, "%d: FAIL: I no longer hold the lock held "
+ "before checkpoint/restart !!! rc %d "
+ "lock_acquired %d\n", tnum, rc, lock_acquired);
+ tstatus[tnum] = 1;
+ }
+
+ if (lock_acquired || !rc)
+ pthread_mutex_unlock(&mutex);
+
+ fprintf(logfp, "%d: Thread %lu: exiting, rc 0\n", tnum,
+ pthread_self());
+ fflush(logfp);
+
+ pthread_exit((void *)&tstatus[tnum]);
+
+}
+
+pthread_t *create_threads(int n)
+{
+ int i;
+ int rc;
+ pthread_t *tid_list;
+ pthread_t tid;
+ pthread_attr_t *attr = NULL;
+
+ tid_list = (pthread_t *)malloc(n * sizeof(pthread_t));
+ tstatus = malloc(sizeof(int) * n);
+
+ if (!tid_list || !tstatus) {
+ fprintf(logfp, "malloc() failed, n %d, error %s\n",
+ n, strerror(errno));
+ do_exit(1);
+ }
+
+ attr = NULL;
+ for (i = 0; i < n; i++) {
+ rc = pthread_create(&tid, attr, do_work, (void *)i);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_create(): i %d, rc %d, "
+ "error %s\n", i, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ tid_list[i] = tid;
+ }
+
+ fprintf(logfp, "Created %d threads\n", n);
+ fflush(logfp);
+
+ return tid_list;
+}
+
+int wait_for_threads(pthread_t *tid_list, int n)
+{
+ int i;
+ int rc;
+ int status;
+ int *statusp;
+ int exit_status;
+
+ exit_status = 0;
+ for (i = 0; i < n; i++) {
+ rc = pthread_join(tid_list[i], (void **)&statusp);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_join() failed, i %d, rc %d "
+ "error %s\n", i, rc, strerror(errno));
+ do_exit(1);
+ }
+
+ fprintf(logfp, "i %d: *statusp %x\n", i, *statusp);
+ fflush(logfp);
+
+ if (*statusp)
+ exit_status = 1;
+ }
+
+ return exit_status;
+}
+
+init_mutex(pthread_mutex_t *mutex)
+{
+ int rc;
+ pthread_mutexattr_t mutex_attr;
+
+ rc = pthread_mutexattr_init(&mutex_attr);
+ if (rc) {
+ fprintf(logfp, "pthread_mutexattr_init() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+
+ rc = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
+ if (rc) {
+ fprintf(logfp, "pthread_mutexattr_settype() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * TODO: Change other attributes of the mutex to non-default values ?
+ */
+
+ rc = pthread_mutex_init(mutex, &mutex_attr);
+ if (rc) {
+ fprintf(logfp, "pthread_mutex_init() failed, rc %d, error %s\n",
+ rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+main(int argc, char *argv[])
+{
+ int c;
+ int i;
+ int rc;
+ int status;
+ pthread_t *tid_list;
+ char log_file[256];
+
+ sprintf(log_file, "%s.log", LOG_PREFIX);
+
+ if (test_done()) {
+ fprintf(stderr, "Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ while ((c = getopt(argc, argv, "hn:")) != EOF) {
+ switch (c) {
+ case 'n': num_threads = atoi(optarg); break;
+ case 'h':
+ default:
+ usage(argv);
+ }
+ };
+
+ logfp = fopen(log_file, "w");
+ if (!logfp) {
+ fprintf(stderr, "fopen(%s) failed, %s\n", log_file,
+ strerror(errno));
+ fflush(stderr);
+ do_exit(1);
+ }
+
+ fprintf(stderr, "Redirecting output to %s\n", log_file);
+ fflush(stderr);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+
+ /*
+ * Create a barrier which the main-thread can use to determine
+ * when all threads are ready for checkpoint.
+ */
+ rc = pthread_barrier_init(&cr_ready, NULL, num_threads+1);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_barrier_init() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+
+ rc = pthread_barrier_init(&threads_created, NULL, num_threads);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_barrier_init() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+
+ init_mutex(&mutex);
+
+ tid_list = create_threads(num_threads);
+
+ /*
+ * Wait for everyone to be ready for checkpoint
+ */
+ pthread_barrier_wait(&cr_ready);
+ if (rc != PTHREAD_BARRIER_SERIAL_THREAD && rc != 0) {
+ fprintf(logfp, "main: pthread_barrier_wait() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * Now that we closed the special files and created the threads,
+ * tell any wrapper scripts, we are ready for checkpoint
+ */
+ set_checkpoint_ready();
+
+ rc = wait_for_threads(tid_list, num_threads);
+
+ fprintf(logfp, "Exiting with status %d\n", rc);
+
+ do_exit(rc);
+}
--
1.6.0.4
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list