[Devel] [PATCH][cr-tests] pthread2: Test additional pthread attributes
Sukadev Bhattiprolu
sukadev at linux.vnet.ibm.com
Fri Jan 8 17:29:24 PST 2010
This test case currently fails with following errors in dmesg:
Looks like the VM_NORESERVE flag on some maps triggers the error
(CKPT_VMA_NOT_SUPPORTED includes the VM_NORESERVE flag)
[4999:4999:c/r:checkpoint_vmas:625] vma 0xb7200000-0xb7221000 flags
0x200073
[err -38][pos 102940][E @ checkpoint_vmas:629][pid 4976 tsk pthread2]
vma: bad flags (0x200073)
[4999:4999:c/r:checkpoint_task_objs:264] mm: objref -38
[4999:4999:c/r:ckpt_write_obj_type:66] type 9999 len 8
[4999:4999:c/r:ckpt_write_obj_type:66] type 5 len 93
[err -38][pos 102940][E @ checkpoint_task_objs:266][pid 4976 tsk
pthread2]mm_struct
[4999:4999:c/r:checkpoint_task:450] objs -38
[4999:4999:c/r:pgarr_release_pages:101] total pages 0
---
From: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
Date: Sat, 26 Dec 2009 13:08:32 +0530
Subject: [PATCH 1/3] pthread2: Test additional pthread attributes
Extend the test case to test all (most) pthread attributes in a single
test.
Signed-off-by: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
---
process-tree/pthread2.c | 400 +++++++++++++++++++++++++++++++++++++-----
process-tree/run-pthread2.sh | 5 +-
2 files changed, 355 insertions(+), 50 deletions(-)
diff --git a/process-tree/pthread2.c b/process-tree/pthread2.c
index 6ac1e52..a773245 100644
--- a/process-tree/pthread2.c
+++ b/process-tree/pthread2.c
@@ -12,11 +12,10 @@
#define LOG_PREFIX "logs.d/pthread2"
FILE *logfp;
-
int num_threads = 8;
-void **exp_addrs;
-size_t *exp_sizes;
int *tstatus;
+pthread_barrier_t barrier;
+pthread_mutex_t dump_lock;
static void usage(char *argv[])
{
@@ -25,19 +24,10 @@ static void usage(char *argv[])
do_exit(1);
}
-pthread_attr_t *get_thread_attr(int tnum)
+pthread_attr_t *alloc_thread_attr()
{
- int rc, size;
+ int rc;
pthread_attr_t *attr;
- void *stack;
-
- size = MIN_STACK_SIZE + (tnum * getpagesize());
-
- stack = malloc(size);
- if (!stack) {
- fprintf(logfp, "malloc(stack): error %s\n", strerror(errno));
- do_exit(1);
- }
attr = malloc(sizeof(pthread_attr_t));
if (!attr) {
@@ -52,29 +42,211 @@ pthread_attr_t *get_thread_attr(int tnum)
do_exit(1);
}
- rc = pthread_attr_setstack(attr, stack, size);
+ return attr;
+}
+
+#ifndef debug
+dump_attr(char *msg, pthread_attr_t *attr)
+{
+}
+#endif
+
+get_affinity(int tnum, pthread_attr_t *attr, cpu_set_t *cpu_set)
+{
+ int rc;
+
+ fprintf(logfp, "sizeof(cpu_set_t) %d\n", sizeof(cpu_set_t));
+
+ rc = pthread_attr_getaffinity_np(attr, sizeof(cpu_set_t), cpu_set);
if (rc < 0) {
- fprintf(logfp, "pthread_attr_setstack(): rc %d error %s\n",
- rc, strerror(errno));
+ fprintf(logfp, "pthread_attr_getaffin() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
do_exit(1);
}
- return attr;
}
-int get_stack_info(pthread_t tid, void **addrp, size_t *sizep)
+compare_affinity(int tnum, pthread_attr_t *exp_attr, pthread_attr_t *act_attr)
+{
+ cpu_set_t exp_cpus, act_cpus;
+
+ get_affinity(tnum, exp_attr, &exp_cpus);
+ get_affinity(tnum, act_attr, &act_cpus);
+
+ if (memcmp(&exp_cpus, &act_cpus, sizeof(cpu_set_t))) {
+ fprintf(logfp, "cpu set mismatch\n");
+ do_exit(1);
+ }
+}
+
+get_detachstate(int tnum, pthread_attr_t *attr, int *state)
{
int rc;
- pthread_attr_t attr;
- rc = pthread_getattr_np(tid, &attr);
+ rc = pthread_attr_getdetachstate(attr, state);
if (rc < 0) {
- fprintf(logfp, "pthread_getattr_np failed, rc %d, %s\n", rc,
- strerror(errno));
- pthread_exit(ERROR_EXIT);
+ fprintf(logfp, "pthread_attr_getdetachstate() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+compare_detachstate(int tnum, pthread_attr_t *exp_attr,
+ pthread_attr_t *act_attr)
+{
+
+ int exp_state, act_state;
+
+ get_detachstate(tnum, exp_attr, &exp_state);
+ get_detachstate(tnum, act_attr, &act_state);
+
+ if (exp_state != act_state) {
+ fprintf(logfp, "%d: Thread detach state mismatch: expected %d, "
+ "actual %d\n", tnum, exp_state, act_state);
+ do_exit(1);
+ }
+}
+
+get_guardsize(int tnum, pthread_attr_t *attr, int *gsize)
+{
+ int rc;
+
+ rc = pthread_attr_getguardsize(attr, gsize);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_getguardsize() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+void compare_guardsize(int tnum, pthread_attr_t *exp_attr,
+ pthread_attr_t *act_attr)
+{
+ size_t exp_size, act_size;
+
+ get_guardsize(tnum, exp_attr, &exp_size);
+ get_guardsize(tnum, act_attr, &act_size);
+
+ if (exp_size != act_size) {
+ fprintf(logfp, "%d: Thread guard size mismatch, expected %d "
+ "actual %d\n", tnum, exp_size, act_size);
+ do_exit(1);
+ }
+}
+
+get_inheritsched(int tnum, pthread_attr_t *attr, int *isched)
+{
+ int rc;
+
+ rc = pthread_attr_getinheritsched(attr, isched);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_inheritsched() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+void compare_inheritsched(int tnum, pthread_attr_t *exp_attr,
+ pthread_attr_t *act_attr)
+{
+ int exp_isched, act_isched;
+
+ get_inheritsched(tnum, exp_attr, &exp_isched);
+ get_inheritsched(tnum, act_attr, &act_isched);
+
+ if (exp_isched != act_isched) {
+ fprintf(logfp, "%d: Thread inherit-sched mismatch, expected %d "
+ "actual %d\n", tnum, exp_isched, act_isched);
+ do_exit(1);
}
+}
- rc = pthread_attr_getstack(&attr, (void **)addrp, sizep);
+get_schedparam(int tnum, pthread_attr_t *attr, int *prio)
+{
+ int rc;
+ struct sched_param param;
+
+ rc = pthread_attr_getschedparam(attr, ¶m);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_getschedparam() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+ *prio = param.__sched_priority;
+}
+
+compare_schedparam(int tnum, pthread_attr_t *exp_attr, pthread_attr_t *act_attr)
+{
+ int exp_prio, act_prio;
+
+ get_schedparam(tnum, exp_attr, &exp_prio);
+ get_schedparam(tnum, act_attr, &act_prio);
+
+ if (exp_prio != act_prio) {
+ fprintf(logfp, "%d: Thread sched-param mismatch, expected %d "
+ "actual %d\n", tnum, exp_prio, act_prio);
+ do_exit(1);
+ }
+}
+
+get_schedpolicy(int tnum, pthread_attr_t *attr, int *policy)
+{
+ int rc;
+
+ rc = pthread_attr_getschedpolicy(attr, policy);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_getschedpolicy() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+compare_schedpolicy(int tnum, pthread_attr_t *exp_attr,
+ pthread_attr_t *act_attr)
+{
+ int exp_policy, act_policy;
+
+ get_schedpolicy(tnum, exp_attr, &exp_policy);
+ get_schedpolicy(tnum, act_attr, &act_policy);
+
+ if (exp_policy != act_policy) {
+ fprintf(logfp, "%d: Thread sched-policy mismatch, expected %d "
+ "actual %d\n", tnum, exp_policy, act_policy);
+ do_exit(1);
+ }
+}
+
+get_scope(int tnum, pthread_attr_t *attr, int *scope)
+{
+ int rc;
+
+ rc = pthread_attr_getscope(attr, scope);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_getscope() failed, rc %d, "
+ "error %s\n", rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+compare_scope(int tnum, pthread_attr_t *exp_attr, pthread_attr_t *act_attr)
+{
+ int exp_scope, act_scope;
+
+ get_scope(tnum, exp_attr, &exp_scope);
+ get_scope(tnum, act_attr, &act_scope);
+
+ if (exp_scope != act_scope) {
+ fprintf(logfp, "%d: Thread scope mismatch, expected %d "
+ "actual %d\n", tnum, exp_scope, act_scope);
+ do_exit(1);
+ }
+}
+
+int get_stack(pthread_attr_t *attr, void **addrp, int *sizep)
+{
+ int rc;
+
+ rc = pthread_attr_getstack(attr, (void **)addrp, sizep);
if (rc < 0) {
fprintf(logfp, "pthread_attr_getstackaddr failed, rc %d, %s\n",
rc, strerror(errno));
@@ -84,40 +256,145 @@ int get_stack_info(pthread_t tid, void **addrp, size_t *sizep)
return 0;
}
+void compare_stack(int tnum, pthread_attr_t *exp_attr,
+ pthread_attr_t *act_attr)
+{
+ int exp_size, act_size;
+ void *exp_addr, *act_addr;
+
+ get_stack(exp_attr, &exp_addr, &exp_size);
+ get_stack(act_attr, &act_addr, &act_size);
+
+ if (act_addr != exp_addr || act_size != exp_size) {
+ fprintf(logfp, "%d: Expected: (%p, %d), actual (%p, %d)\n",
+ tnum, exp_addr, exp_size, act_addr, act_size);
+ fflush(logfp);
+ do_exit(1);
+ }
+}
+
+compare_attr(int tnum, pthread_attr_t *exp_attr, pthread_attr_t *act_attr)
+{
+
+ dump_attr("Expected attr", exp_attr);
+ dump_attr("Actual attr", act_attr);
+
+ /*
+ * We cannot simply memcmp() the exp_attr and act_attr since the
+ * 'struct pthread_attr' contains a pointer to cpuset. This address
+ * will be different even if the cpusets are the same
+ */
+ compare_affinity(tnum, exp_attr, act_attr);
+
+ compare_detachstate(tnum, exp_attr, act_attr);
+
+ compare_guardsize(tnum, exp_attr, act_attr);
+
+ compare_inheritsched(tnum, exp_attr, act_attr);
+
+ compare_schedparam(tnum, exp_attr, act_attr);
+
+ compare_schedpolicy(tnum, exp_attr, act_attr);
+
+ compare_scope(tnum, exp_attr, act_attr);
+
+ compare_stack(tnum, exp_attr, act_attr);
+}
+
void *do_work(void *arg)
{
long tnum = (long)arg;
int rc;
- void *act_addr;
- size_t act_size;
+ pthread_attr_t exp_attr, act_attr;
fprintf(logfp, "%ld: Thread %lu: waiting for checkpoint\n", tnum,
pthread_self());
fflush(logfp);
+ memset(&exp_attr, 0, sizeof(pthread_attr_t));
+ memset(&act_attr, 0, sizeof(pthread_attr_t));
+
+ /*
+ * Collect attributes before checkpoint/restart.
+ */
+ rc = pthread_getattr_np(pthread_self(), &exp_attr);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_getattr_np failed, rc %d, %s\n", rc,
+ strerror(errno));
+ pthread_exit(ERROR_EXIT);
+ }
+
+ /*
+ * Inform main-thread we are ready for checkpoint.
+ */
+ rc = pthread_barrier_wait(&barrier);
+ 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 = get_stack_info(pthread_self(), &act_addr, &act_size);
- if (rc < 0)
+ /*
+ * Collect attributes after checkpoint/restart.
+ */
+ rc = pthread_getattr_np(pthread_self(), &act_attr);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_getattr_np failed, rc %d, %s\n", rc,
+ strerror(errno));
pthread_exit(ERROR_EXIT);
-
- if (act_addr != exp_addrs[tnum] || act_size != exp_sizes[tnum]) {
- fprintf(logfp, "%d: Expected: (%p, %d), actual (%p, %d)\n",
- tnum, exp_addrs[tnum], exp_sizes[tnum],
- act_addr, act_size);
- fflush(logfp);
- rc = 1;
}
- fprintf(logfp, "%d: Thread %lu: exiting, rc %d\n", tnum,
- pthread_self(), rc);
+ /*
+ * Compare attributes before and after C/R.
+ */
+ compare_attr(tnum, &exp_attr, &act_attr);
+
+ fprintf(logfp, "%d: Thread %lu: exiting, rc 0\n", tnum,
+ pthread_self());
fflush(logfp);
- tstatus[tnum] = rc;
+ tstatus[tnum] = 0;
pthread_exit((void *)&tstatus[tnum]);
}
+void set_stack(pthread_attr_t *attr, int tnum)
+{
+ int rc, size;
+ void *stack;
+
+ size = MIN_STACK_SIZE + (tnum * getpagesize());
+
+ stack = malloc(size);
+ if (!stack) {
+ fprintf(logfp, "malloc(stack): error %s\n", strerror(errno));
+ do_exit(1);
+ }
+
+ rc = pthread_attr_setstack(attr, stack, size);
+ if (rc < 0) {
+ fprintf(logfp, "pthread_attr_setstack(): rc %d error %s\n",
+ rc, strerror(errno));
+ do_exit(1);
+ }
+}
+
+/*
+ * Modify any attributes for this thread for testing.
+ * For now, we only modify the thread-stack.
+ */
+void set_thread_attrs(pthread_attr_t *attr, int tnum)
+{
+ set_stack(attr, tnum);
+
+ return;
+}
+
pthread_t *create_threads(int n)
{
long i;
@@ -127,21 +404,21 @@ pthread_t *create_threads(int n)
pthread_attr_t *attr;
tid_list = (pthread_t *)malloc(n * sizeof(pthread_t));
- exp_addrs = malloc(sizeof(void *) * n);
- exp_sizes = malloc(sizeof(size_t) * n);
tstatus = malloc(sizeof(int) * n);
- if (!tid_list || !exp_addrs || !exp_sizes || !tstatus) {
+ if (!tid_list || !tstatus) {
fprintf(logfp, "malloc() failed, n %d, error %s\n",
n, strerror(errno));
do_exit(1);
}
for (i = 0; i < n; i++) {
- attr = get_thread_attr(i);
+ attr = alloc_thread_attr();
if (!attr)
do_exit(1);
+ set_thread_attrs(attr, i);
+
rc = pthread_create(&tid, attr, do_work, (void *)i);
if (rc < 0) {
fprintf(logfp, "pthread_create(): i %d, rc %d, "
@@ -149,10 +426,6 @@ pthread_t *create_threads(int n)
do_exit(1);
}
- rc = get_stack_info(tid, &exp_addrs[i], &exp_sizes[i]);
- if (rc < 0)
- do_exit(1);
-
tid_list[i] = tid;
}
@@ -224,15 +497,46 @@ main(int argc, char *argv[])
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(&barrier, 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_mutex_init(&dump_lock, NULL);
+ if (rc) {
+ fprintf(logfp, "pthread_mutex_init() failed, rc %d, error %s\n",
+ rc, strerror(errno));
+ do_exit(1);
+ }
+
tid_list = create_threads(num_threads);
/*
+ * Wait for everyone to be ready for checkpoint
+ */
+ pthread_barrier_wait(&barrier);
+ 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
*/
@@ -240,5 +544,7 @@ main(int argc, char *argv[])
rc = wait_for_threads(tid_list, num_threads);
+ fprintf(logfp, "Exiting with status %d\n", rc);
+
do_exit(rc);
}
diff --git a/process-tree/run-pthread2.sh b/process-tree/run-pthread2.sh
index 0686cbd..ff7f0ac 100755
--- a/process-tree/run-pthread2.sh
+++ b/process-tree/run-pthread2.sh
@@ -2,8 +2,7 @@
source ../common.sh
-#dir=`mktemp -p . -d -t cr_pthread2_XXXXXXX` || (echo "mktemp failed"; exit 1)
-dir=cr_pthread2
+dir=`mktemp -p . -d -t cr_pthread2_XXXXXXX` || (echo "mktemp failed"; exit 1)
mkdir $dir
echo "Using output dir $dir"
cd $dir
@@ -17,7 +16,7 @@ RESTART=`which restart`
ECHO="/bin/echo -e"
TEST_CMD="../pthread2"
-TEST_ARGS="-n 128" # -n: number of threads
+TEST_ARGS="-n 4" # -n: number of threads
SCRIPT_LOG="log-run-pthread2"
TEST_PID_FILE="pid.pthread2";
--
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