Commit 037495e4 authored by Florian Bezdeka's avatar Florian Bezdeka Committed by Jan Kiszka
Browse files

y2038: testsuite/smokey/y2038: Adding test cases for mutex_timedlock64()



This patch was based on the patch sent out by Song and reworked.
Especially
  - switched from CLOCK_MONOTONIC to CLOCK_REALTIME
    According to POSIX this service is based on CLOCK_REALTIME

  - Fixed some mutex leaks / missing pthread_mutex_destroy()

  - Removed some magic numbers used for making sure the syscall does
    not return too early

  - Fixed several mutex deadlocks. Once mutex_timedlock() was
    successful following calls will deadlock (as long as no special
    DEADLOCK mutex is being used)
Signed-off-by: default avatarFlorian Bezdeka <florian.bezdeka@siemens.com>
[Jan: resolve compiler warning about uninitialized t1, fix join result evaluation]
Signed-off-by: Jan Kiszka's avatarJan Kiszka <jan.kiszka@siemens.com>
parent 31773eb7
...@@ -115,6 +115,45 @@ static inline bool ts_less(const struct xn_timespec64 *a, ...@@ -115,6 +115,45 @@ static inline bool ts_less(const struct xn_timespec64 *a,
return false; return false;
} }
/**
* Simple helper data structure for holding a thread context
*/
struct thread_context {
int sc_nr;
pthread_mutex_t *mutex;
struct xn_timespec64 *ts;
bool timedwait_timecheck;
};
/**
* Start the supplied function inside a separate thread, wait for completion
* and check the thread return value.
*
* @param thread The thread entry point
* @param arg The thread arguments
* @param exp_result The expected return value
*
* @return 0 if the thread reported @exp_result as return value, the thread's
* return value otherwise
*/
static int run_thread(void *(*thread)(void *), void *arg, int exp_result)
{
pthread_t tid;
void *status;
long res;
int ret;
if (!__T(ret, pthread_create(&tid, NULL, thread, arg)))
return ret;
if (!__T(ret, pthread_join(tid, &status)))
return ret;
res = (long)status;
return (res == exp_result) ? 0 : ret;
}
static int test_sc_cobalt_sem_timedwait64(void) static int test_sc_cobalt_sem_timedwait64(void)
{ {
int ret; int ret;
...@@ -404,6 +443,151 @@ static int test_sc_cobalt_clock_adjtime64(void) ...@@ -404,6 +443,151 @@ static int test_sc_cobalt_clock_adjtime64(void)
return 0; return 0;
} }
static void *timedlock64_thread(void *arg)
{
struct thread_context *ctx = (struct thread_context *) arg;
struct xn_timespec64 t1 = {}; /* silence compiler warning */
struct xn_timespec64 t2;
struct timespec ts_nat;
int ret;
if (ctx->timedwait_timecheck) {
if (!__T(ret, clock_gettime(CLOCK_REALTIME, &ts_nat)))
return (void *)(long)ret;
t1.tv_sec = ts_nat.tv_sec;
t1.tv_nsec = ts_nat.tv_nsec;
ts_add_ns(&t1, ctx->ts->tv_nsec);
ts_add_ns(&t1, ctx->ts->tv_sec * NSEC_PER_SEC);
}
ret = XENOMAI_SYSCALL2(ctx->sc_nr, ctx->mutex, (void *) ctx->ts);
if (ret)
return (void *)(long)ret;
if (ctx->timedwait_timecheck) {
if (!__T(ret, clock_gettime(CLOCK_REALTIME, &ts_nat)))
return (void *)(long)ret;
t2.tv_sec = ts_nat.tv_sec;
t2.tv_nsec = ts_nat.tv_nsec;
if (ts_less(&t2, &t1))
smokey_warning("mutex_timedlock64 returned too early!\n"
"Expected wakeup at: %lld sec %lld nsec\n"
"Back at : %lld sec %lld nsec\n",
t1.tv_sec, t1.tv_nsec, t2.tv_sec,
t2.tv_nsec);
}
return (void *)(long)pthread_mutex_unlock(ctx->mutex);
}
static int test_sc_cobalt_mutex_timedlock64(void)
{
int ret;
pthread_mutex_t mutex;
int sc_nr = sc_cobalt_mutex_timedlock64;
struct xn_timespec64 ts64;
struct thread_context ctx = {0};
ret = pthread_mutex_init(&mutex, NULL);
/* Make sure we don't crash because of NULL pointers */
ret = XENOMAI_SYSCALL2(sc_nr, NULL, NULL);
if (ret == -ENOSYS) {
smokey_note("mutex_timedlock64: skipped. (no kernel support)");
return 0; // Not implemented, nothing to test, success
}
if (!smokey_assert(ret == -EINVAL))
return ret ? ret : -EINVAL;
/*
* mutex can be taken immediately, no need to validate
* NULL should be allowed
*/
ret = XENOMAI_SYSCALL2(sc_nr, &mutex, NULL);
if (!smokey_assert(!ret))
return ret;
if (!__T(ret, pthread_mutex_unlock(&mutex)))
return ret;
/*
* mutex can be taken immediately, no need to validate
* an invalid address should be allowed
*/
ret = XENOMAI_SYSCALL2(sc_nr, &mutex, 0xdeadbeef);
if (!smokey_assert(!ret))
return ret;
/*
* mutex still locked, second thread has to fail with -EINVAL when
* submitting NULL as timeout
*/
ctx.sc_nr = sc_nr;
ctx.mutex = &mutex;
ctx.ts = NULL;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, -EINVAL)))
return ret;
/*
* mutex still locked, second thread has to fail with -EFAULT when
* submitting an invalid address as timeout
*/
ctx.ts = (void *) 0xdeadbeef;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, -EFAULT)))
return ret;
/*
* mutex still locked, second thread has to fail with -EFAULT when
* submitting an invalid timeout (while the address is valid)
*/
ts64.tv_sec = -1;
ctx.ts = &ts64;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, -EFAULT)))
return ret;
/*
* mutex still locked, second thread has to fail with -ETIMEOUT when
* submitting a valid timeout
*/
ts64.tv_sec = 0;
ts64.tv_nsec = 500;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, -ETIMEDOUT)))
return ret;
if (!__T(ret, pthread_mutex_unlock(&mutex)))
return ret;
/* mutex available, second thread should be able to lock and unlock */
ts64.tv_sec = 0;
ts64.tv_nsec = 500;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, 0)))
return ret;
/*
* Locking the mutex here so the second thread has to deliver -ETIMEOUT.
* Timechecks will now be enabled to make sure we don't give up to early
*/
if (!__T(ret, pthread_mutex_lock(&mutex)))
return ret;
ts64.tv_sec = 0;
ts64.tv_nsec = 500;
ctx.timedwait_timecheck = true;
if (!__T(ret, run_thread(timedlock64_thread, &ctx, -ETIMEDOUT)))
return ret;
if (!__T(ret, pthread_mutex_unlock(&mutex)))
return ret;
if (!__T(ret, pthread_mutex_destroy(&mutex)))
return ret;
return 0;
}
static int run_y2038(struct smokey_test *t, int argc, char *const argv[]) static int run_y2038(struct smokey_test *t, int argc, char *const argv[])
{ {
int ret; int ret;
...@@ -432,5 +616,9 @@ static int run_y2038(struct smokey_test *t, int argc, char *const argv[]) ...@@ -432,5 +616,9 @@ static int run_y2038(struct smokey_test *t, int argc, char *const argv[])
if (ret) if (ret)
return ret; return ret;
ret = test_sc_cobalt_mutex_timedlock64();
if (ret)
return ret;
return 0; return 0;
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment