--- /dev/null
+/* testing pthread mutex behaviour with various attributes */
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "test.h"
+
+#define T(f) if ((r=(f))) t_error(#f " failed: %s\n", strerror(r))
+#define E(f) if (f) t_error(#f " failed: %s\n", strerror(errno))
+
+static void *relock(void *arg)
+{
+ void **a = arg;
+ int r;
+
+ T(pthread_mutex_lock(a[0]));
+ E(sem_post(a[1]));
+ *(int*)a[2] = pthread_mutex_lock(a[0]);
+ E(sem_post(a[1]));
+
+ T(pthread_mutex_unlock(a[0]));
+ if (*(int*)a[2] == 0)
+ T(pthread_mutex_unlock(a[0]));
+ return 0;
+}
+
+static int test_relock(int mtype)
+{
+ struct timespec ts;
+ pthread_t t;
+ pthread_mutex_t m;
+ pthread_mutexattr_t ma;
+ sem_t s;
+ int i;
+ int r;
+ void *p;
+ void *a[] = {&m,&s,&i};
+
+ T(pthread_mutexattr_init(&ma));
+ T(pthread_mutexattr_settype(&ma, mtype));
+ T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
+ T(pthread_mutex_init(a[0], &ma));
+ T(pthread_mutexattr_destroy(&ma));
+ E(sem_init(a[1], 0, 0));
+ T(pthread_create(&t, 0, relock, a));
+ E(sem_wait(a[1]));
+ E(clock_gettime(CLOCK_REALTIME, &ts));
+ ts.tv_nsec += 100*1000*1000;
+ if (ts.tv_nsec >= 1000*1000*1000) {
+ ts.tv_nsec -= 1000*1000*1000;
+ ts.tv_sec += 1;
+ }
+ r = sem_timedwait(a[1],&ts);
+ if (r == -1) {
+ if (errno != ETIMEDOUT)
+ t_error("sem_timedwait failed with unexpected error: %s\n", strerror(errno));
+ /* leave the deadlocked relock thread running */
+ return -1;
+ }
+ T(pthread_join(t, &p));
+ T(pthread_mutex_destroy(a[0]));
+ E(sem_destroy(a[1]));
+ return i;
+}
+
+static void *unlock(void *arg)
+{
+ void **a = arg;
+
+ *(int*)a[1] = pthread_mutex_unlock(a[0]);
+ return 0;
+}
+
+static int test_unlock(int mtype)
+{
+ pthread_t t;
+ pthread_mutex_t m;
+ pthread_mutexattr_t ma;
+ int i;
+ int r;
+ void *p;
+ void *a[] = {&m,&i};
+
+ T(pthread_mutexattr_init(&ma));
+ T(pthread_mutexattr_settype(&ma, mtype));
+ T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
+ T(pthread_mutex_init(a[0], &ma));
+ T(pthread_mutexattr_destroy(&ma));
+ T(pthread_create(&t, 0, unlock, a));
+ T(pthread_join(t, &p));
+ T(pthread_mutex_destroy(a[0]));
+ return i;
+}
+
+static int test_unlock_other(int mtype)
+{
+ pthread_t t;
+ pthread_mutex_t m;
+ pthread_mutexattr_t ma;
+ int i;
+ int r;
+ void *p;
+ void *a[] = {&m,&i};
+
+ T(pthread_mutexattr_init(&ma));
+ T(pthread_mutexattr_settype(&ma, mtype));
+ T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
+ T(pthread_mutex_init(a[0], &ma));
+ T(pthread_mutexattr_destroy(&ma));
+ T(pthread_mutex_lock(a[0]));
+ T(pthread_create(&t, 0, unlock, a));
+ T(pthread_join(t, &p));
+ T(pthread_mutex_unlock(a[0]));
+ T(pthread_mutex_destroy(a[0]));
+ return i;
+}
+
+static void test_mutexattr()
+{
+ pthread_mutex_t m;
+ pthread_mutexattr_t a;
+ int r;
+ int i;
+
+ T(pthread_mutexattr_init(&a));
+ T(pthread_mutexattr_gettype(&a, &i));
+ if (i != PTHREAD_MUTEX_DEFAULT)
+ t_error("default mutex type is %d, wanted PTHREAD_MUTEX_DEFAULT (%d)\n", i, PTHREAD_MUTEX_DEFAULT);
+ T(pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK));
+ T(pthread_mutexattr_gettype(&a, &i));
+ if (i != PTHREAD_MUTEX_ERRORCHECK)
+ t_error("setting error check mutex type failed failed: got %d, wanted %d\n", i, PTHREAD_MUTEX_ERRORCHECK);
+ T(pthread_mutexattr_destroy(&a));
+}
+
+int main(void)
+{
+ int i;
+
+ test_mutexattr();
+
+ i = test_relock(PTHREAD_MUTEX_NORMAL);
+ if (i != -1)
+ t_error("PTHREAD_MUTEX_NORMAL relock did not deadlock, got %s\n", strerror(i));
+ i = test_relock(PTHREAD_MUTEX_ERRORCHECK);
+ if (i != EDEADLK)
+ t_error("PTHREAD_MUTEX_ERRORCHECK relock did not return EDEADLK, got %s\n", i==-1?"deadlock":strerror(i));
+ i = test_relock(PTHREAD_MUTEX_RECURSIVE);
+ if (i != 0)
+ t_error("PTHREAD_MUTEX_RECURSIVE relock did not succed, got %s\n", i==-1?"deadlock":strerror(i));
+
+ i = test_unlock(PTHREAD_MUTEX_ERRORCHECK);
+ if (i != EPERM)
+ t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
+ i = test_unlock(PTHREAD_MUTEX_RECURSIVE);
+ if (i != EPERM)
+ t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
+
+ i = test_unlock_other(PTHREAD_MUTEX_ERRORCHECK);
+ if (i != EPERM)
+ t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
+ i = test_unlock_other(PTHREAD_MUTEX_RECURSIVE);
+ if (i != EPERM)
+ t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
+
+ return t_status;
+}
#include "test.h"
#define TEST(r, f, m) ( \
- ((r) = (f)) == 0 || (t_error("%s failed: (pshared==%d) %s (" m ")\n", #f, pshared, strerror(r)), 0) )
+ ((r) = (f)) == 0 || (t_error("%s failed: (pshared==%d, pi==%d) %s (" m ")\n", #f, pshared, pi, strerror(r)), 0) )
#define TESTX(r, f, x, m) ( \
- ((r) = (f)) == (x) || (t_error("%s failed: (pshared==%d) got %d \"%s\" want %d \"%s\" (" m ")\n", #f, pshared, r, strerror(r), x, strerror(x)), 0) )
-
-static int pshared;
+ ((r) = (f)) == (x) || (t_error("%s failed: (pshared==%d, pi==%d) got %d \"%s\" want %d \"%s\" (" m ")\n", #f, pshared, pi, r, strerror(r), x, strerror(x)), 0) )
static void *start_lock(void *arg)
{
return 0;
}
-void f(void)
+void f(int pshared, int pi)
{
pthread_t td;
int r;
TEST(r, pthread_mutexattr_setrobust(&mtx_a, PTHREAD_MUTEX_ROBUST), "setting robust attribute");
if (pshared)
TEST(r, pthread_mutexattr_setpshared(&mtx_a, PTHREAD_PROCESS_SHARED), "setting pshared attribute");
+ if (pi)
+ TEST(r, pthread_mutexattr_setprotocol(&mtx_a, PTHREAD_PRIO_INHERIT), "setting PI attribute");
TEST(r, pthread_mutex_init(&mtx, &mtx_a), "initializing robust mutex");
TEST(r, pthread_mutex_lock(&mtx), "locking robust mutex");
TEST(r, pthread_mutex_unlock(&mtx), "unlocking robust mutex");
int main(void)
{
- f();
- pshared=1;
- f();
+ for (int pshared=0; pshared<=1; pshared++)
+ for (int pi=0; pi<=1; pi++)
+ f(pshared, pi);
return t_status;
}