Import LinuxCNC source tree
This commit is contained in:
1
tests/lowlevel/emcmot-error-mpsc/expected
Normal file
1
tests/lowlevel/emcmot-error-mpsc/expected
Normal file
@@ -0,0 +1 @@
|
||||
test passed
|
||||
112
tests/lowlevel/emcmot-error-mpsc/test.c
Normal file
112
tests/lowlevel/emcmot-error-mpsc/test.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Concurrency / correctness test for the emcmotError MPSC ring buffer.
|
||||
*
|
||||
* Spawns NPROD producer threads pumping NMSG messages each, plus one
|
||||
* consumer that drains. Verifies every message arrives exactly once
|
||||
* and that messages from each individual producer arrive in producer-
|
||||
* local sequence order. Across producers any interleaving is allowed.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <emcmotcfg.h>
|
||||
#include "motion.h"
|
||||
#include "dbuf.h"
|
||||
#include "stashf.h"
|
||||
#include <rtapi_atomic.h>
|
||||
|
||||
#define NPROD 8
|
||||
#define NMSG 100000
|
||||
|
||||
static emcmot_error_t errlog;
|
||||
static rtapi_atomic_int producers_done = 0;
|
||||
|
||||
static void *producer_fn(void *arg) {
|
||||
long id = (long)arg;
|
||||
char buf[64];
|
||||
for (int i = 0; i < NMSG; i++) {
|
||||
snprintf(buf, sizeof(buf), "P%ld:%010d", id, i);
|
||||
while (emcmotErrorPut(&errlog, buf) < 0) {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
atomic_fetch_add(&producers_done, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *consumer_fn(void *arg) {
|
||||
(void)arg;
|
||||
long total = (long)NPROD * NMSG;
|
||||
long received = 0;
|
||||
int per_producer[NPROD] = {0};
|
||||
char raw[EMCMOT_ERROR_LEN];
|
||||
char msg[EMCMOT_ERROR_LEN];
|
||||
int errors = 0;
|
||||
|
||||
while (received < total) {
|
||||
struct dbuf d;
|
||||
struct dbuf_iter di;
|
||||
/* dbuf_init zero-fills the buffer, so call it BEFORE
|
||||
emcmotErrorGet, which then writes the received bytes in. */
|
||||
dbuf_init(&d, (unsigned char *)raw, EMCMOT_ERROR_LEN);
|
||||
if (emcmotErrorGet(&errlog, raw) == 0) {
|
||||
dbuf_iter_init(&di, &d);
|
||||
if (snprintdbuf(msg, sizeof(msg), &di) < 0) {
|
||||
fprintf(stderr, "snprintdbuf failed\n");
|
||||
errors++;
|
||||
received++;
|
||||
continue;
|
||||
}
|
||||
long pid;
|
||||
int seq;
|
||||
if (sscanf(msg, "P%ld:%d", &pid, &seq) != 2
|
||||
|| pid < 0 || pid >= NPROD) {
|
||||
fprintf(stderr, "bad msg: '%s'\n", msg);
|
||||
errors++;
|
||||
} else if (seq != per_producer[pid]) {
|
||||
fprintf(stderr, "out-of-order P%ld: got %d, want %d\n",
|
||||
pid, seq, per_producer[pid]);
|
||||
errors++;
|
||||
} else {
|
||||
per_producer[pid]++;
|
||||
}
|
||||
received++;
|
||||
} else {
|
||||
if (atomic_load(&producers_done) >= NPROD) {
|
||||
struct timespec ts = {0, 1000000};
|
||||
nanosleep(&ts, NULL);
|
||||
} else {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors == 0) {
|
||||
printf("test passed\n");
|
||||
} else {
|
||||
printf("test FAILED with %d errors\n", errors);
|
||||
}
|
||||
return errors == 0 ? (void *)0 : (void *)1;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
emcmotErrorInit(&errlog);
|
||||
|
||||
pthread_t prods[NPROD];
|
||||
pthread_t cons;
|
||||
pthread_create(&cons, NULL, consumer_fn, NULL);
|
||||
for (long i = 0; i < NPROD; i++) {
|
||||
pthread_create(&prods[i], NULL, producer_fn, (void *)i);
|
||||
}
|
||||
for (long i = 0; i < NPROD; i++) {
|
||||
pthread_join(prods[i], NULL);
|
||||
}
|
||||
void *cret;
|
||||
pthread_join(cons, &cret);
|
||||
return cret ? 1 : 0;
|
||||
}
|
||||
27
tests/lowlevel/emcmot-error-mpsc/test.sh
Executable file
27
tests/lowlevel/emcmot-error-mpsc/test.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
# Concurrency / correctness test for the emcmotError MPSC ring buffer.
|
||||
# RIP-only: builds the test driver against the in-tree motion sources.
|
||||
|
||||
SCRIPTDIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
TOPDIR="$(cd "$SCRIPTDIR/../../.." && pwd)"
|
||||
SRCDIR="${TOPDIR}/src/emc/motion"
|
||||
INCDIR="${TOPDIR}/include"
|
||||
|
||||
if [ ! -f "${SRCDIR}/emcmotutil.c" ]; then
|
||||
echo "skip: motion sources not found (RIP build required)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
gcc -O -pthread -DULAPI -Wall \
|
||||
-I"${INCDIR}" \
|
||||
-I"${SRCDIR}" \
|
||||
"${SCRIPTDIR}/test.c" \
|
||||
"${SRCDIR}/emcmotutil.c" \
|
||||
"${SRCDIR}/dbuf.c" \
|
||||
"${SRCDIR}/stashf.c" \
|
||||
-o "${SCRIPTDIR}/test" || { echo "compile failed"; exit 1; }
|
||||
|
||||
"${SCRIPTDIR}/test"
|
||||
exitval=$?
|
||||
rm -f "${SCRIPTDIR}/test"
|
||||
exit $exitval
|
||||
2
tests/lowlevel/mutex/expected
Normal file
2
tests/lowlevel/mutex/expected
Normal file
@@ -0,0 +1,2 @@
|
||||
count=200000
|
||||
test passed
|
||||
38
tests/lowlevel/mutex/test.c
Normal file
38
tests/lowlevel/mutex/test.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <rtapi_mutex.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// to make this test fail, you can...
|
||||
#if 0
|
||||
#define rtapi_mutex_give(x) (void)0
|
||||
#define rtapi_mutex_get(x) (void)0
|
||||
#endif
|
||||
|
||||
const unsigned int N = 100000;
|
||||
unsigned long mut;
|
||||
unsigned long count;
|
||||
|
||||
void *thread_fun(void *unused) {
|
||||
for(unsigned long i=0; i<N; i++) {
|
||||
rtapi_mutex_get(&mut);
|
||||
unsigned long tmp = count;
|
||||
tmp++;
|
||||
sched_yield();
|
||||
count = tmp;
|
||||
rtapi_mutex_give(&mut);
|
||||
}
|
||||
return unused;
|
||||
}
|
||||
|
||||
int main() {
|
||||
pthread_t t1, t2;
|
||||
pthread_create(&t1, NULL, thread_fun, NULL);
|
||||
pthread_create(&t2, NULL, thread_fun, NULL);
|
||||
pthread_join(t1, NULL);
|
||||
pthread_join(t2, NULL);
|
||||
printf("count=%lu\n", count);
|
||||
assert(count == 2*N);
|
||||
printf("test passed\n");
|
||||
return 0;
|
||||
}
|
||||
5
tests/lowlevel/mutex/test.sh
Executable file
5
tests/lowlevel/mutex/test.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
gcc -O -I"${HEADERS}" test.c -o test -DULAPI -std=gnu99 -pthread || exit 1
|
||||
./test; exitval=$?
|
||||
rm -f test
|
||||
exit $exitval
|
||||
Reference in New Issue
Block a user