1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
@mindmaze_header@
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "threaddata-manipulation.h"
#include "mmpredefs.h"
#include "mmtime.h"
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#ifdef _MSC_VER
# include <intrin.h>
# define _Atomic
# define atomic_store_i64(obj, val) _InterlockedExchange64(obj, val)
# define atomic_fetch_sub_i64(obj, val) _InterlockedExchangeAdd64(obj, -val)
#else
# include <stdatomic.h>
# define atomic_store_i64(obj, val) atomic_store(obj, val)
# define atomic_fetch_sub_i64(obj, val) atomic_fetch_sub(obj, val)
#endif
/**
* touch_data() - modify data and restore it
* @data: address of shared data to modify
* @tid: data identifying uniquely the calling thread
* @do_sleep: if true, sleep between data modification and data value restoration
*
* Return: true if no inconsistency has been detected, false otherwise
*/
static
bool touch_data(_Atomic int64_t* data, int64_t tid, bool do_sleep)
{
int64_t prev;
atomic_store_i64(data, tid);
if (do_sleep)
mm_relative_sleep_ms(1);
prev = atomic_fetch_sub_i64(data, tid);
return (prev == tid) ? true : false;
}
/**
* run_write_shared_data() - run thread function for concurrent write test
* @shdata: structure holding test setup and shared data
*
* In each iteration, lock the mutex, touch the shared data (modify and
* restore its value), and unlock the mutex. If an inconsistent state of the
* shared value is detect while touch the data, it means the mutex failed to
* protect and the test fails (reported in @shdata->failed).
*/
API_EXPORTED
intptr_t run_write_shared_data(struct shared_write_data* shdata)
{
int i;
int num_iter = shdata->num_iteration;
_Atomic int64_t* data = &shdata->value;
int64_t tid = (int64_t)mm_thr_self();
bool match, do_sleep;
do_sleep = shdata->sleep_in_touch;
for (i = 0; i < num_iter; i++) {
mm_thr_mutex_lock(&shdata->mutex);
match = touch_data(data, tid, do_sleep);
mm_thr_mutex_unlock(&shdata->mutex);
if (!match) {
shdata->failed = true;
break;
}
}
atomic_fetch_sub_i64(&shdata->num_runner_remaining, 1);
return 0;
}
API_EXPORTED
intptr_t run_notif_data(struct notif_data* ndata)
{
mm_thr_mutex_lock(&ndata->mutex);
// Notify that the runner is ready
ndata->nwaiter += 1;
mm_thr_cond_signal(&ndata->cv1);
// Wait for being signal or asked to exit
while (!ndata->todo && !ndata->quit)
mm_thr_cond_wait(&ndata->cv2, &ndata->mutex);
if (!ndata->quit)
ndata->done += 1;
ndata->numquit += 1;
mm_thr_mutex_unlock(&ndata->mutex);
return 0;
}
API_EXPORTED
intptr_t run_robust_mutex_write_data(struct robust_mutex_write_data* rdata)
{
int r, iter;
mm_thr_mutex_t* mtx = &rdata->mutex;
r = mm_thr_mutex_lock(mtx);
if (r == EOWNERDEAD) {
rdata->detected_iter_after_crash = rdata->iter_finished;
mm_thr_mutex_consistent(mtx);
} else if (r != 0) {
return -1;
}
iter = rdata->iter++;
if (iter == 0 && rdata->sleep_after_first_lock)
mm_relative_sleep_ms(50);
if (iter == rdata->crash_at_iter) {
abort();
}
rdata->iter_finished++;
mm_thr_mutex_unlock(mtx);
return 0;
}
|