EXPERIMENT / 配套代码
home_test.c
← 返回文章/* Compile with -Wl,--wrap=ioctl. Exercise user-space sequencing and cancellation. */
static long long current;
static unsigned travel, moves, stops, calls, inject, fault;
static int stale;
int __wrap_ioctl(int fd, unsigned long cmd, ...)
{
va_list args;
void *p;
(void)fd;
va_start(args, cmd); p = va_arg(args, void *); va_end(args);
calls++;
if (inject && calls == inject) {
if (fault == 1) { errno = EIO; return -1; }
if (fault == 2) interrupted = 1;
if (fault == 3) stale = 1;
}
if (stale && cmd != PTZ_STATUS && cmd != PTZ_GET_POSITION) {
errno = ESTALE; return -1;
}
switch (cmd) {
case PTZ_GUARD: break;
case PTZ_STOP: stops++; break;
case PTZ_SET_TRAVEL:
travel = ((struct ptz_travel *)p)->max_steps;
assert(current >= 0 && current <= travel);
break;
case PTZ_SET_POSITION:
current = ((struct ptz_set_position *)p)->position;
assert(current >= 0 && current <= travel);
break;
case PTZ_MOVE_TO: {
const struct ptz_move_to *to = p;
if (!moves) assert(current == 4200 && travel == 4200 && !to->target);
else assert(moves == 1 && current == 0 && travel == 4039 && to->target == 2020);
current = to->target; moves++;
break;
}
case PTZ_STATUS:
memset(p, 0, sizeof(struct ptz_status));
((struct ptz_status *)p)->axis[0].position = current;
((struct ptz_status *)p)->axis[0].superseded = stale;
break;
case PTZ_GET_POSITION:
memset(p, 0, sizeof(struct ptz_positions));
((struct ptz_positions *)p)->axis[0].position = current;
break;
default: assert(0);
}
return 0;
}
static void reset(void)
{
current = 100; travel = 4039;
moves = stops = calls = 0;
interrupted = stale = 0;
}
int main(void)
{
struct ptz_home h = {0, 1, 4200, 4039};
unsigned total, n;
reset();
assert(!run_home(1, &h, 100));
assert(moves == 2 && current == 2020 && travel == 4039 && stops == 1);
total = calls;
/* Replacement at every ioctl boundary, including the zero-to-center gap,
* must abort the old sequence and cannot stop a newer motion. */
for (n = 1; n <= total; n++) {
reset(); inject = n; fault = 3;
assert(run_home(1, &h, 100) == -ESTALE);
assert(stale && moves <= (n > 10 ? 2U : 1U));
assert(stops == (n > 2 ? 1U : 0U));
}
reset(); inject = 6; fault = 1;
assert(run_home(1, &h, 100) == -EIO && moves == 0 && stops == 2);
reset(); inject = 5; fault = 2;
assert(run_home(1, &h, 100) == -EINTR && moves == 0 && stops == 2);
puts("PASS: user-space home, center, errors, interrupt, replacement at every ioctl boundary");
return 0;
}