Module: xenomai-3 Branch: next Commit: 7ef97138f15a89efa19d41aa3c5a78184ddbbc1b URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=7ef97138f15a89efa19d41aa3c5a78184ddbbc1b
Author: Philippe Gerum <r...@xenomai.org> Date: Sat Feb 27 18:52:35 2016 +0100 drivers/testing: rtdm: add actor task device This is for unit testing in task context. The actor task performs simple test requests issued by userland. --- include/rtdm/uapi/testing.h | 5 ++ kernel/drivers/testing/rtdmtest.c | 169 +++++++++++++++++++++++++++++++------ 2 files changed, 147 insertions(+), 27 deletions(-) diff --git a/include/rtdm/uapi/testing.h b/include/rtdm/uapi/testing.h index 710bea8..76da5ee 100644 --- a/include/rtdm/uapi/testing.h +++ b/include/rtdm/uapi/testing.h @@ -83,6 +83,7 @@ struct rttst_swtest_error { #define RTTST_RTDM_NORMAL_CLOSE 0 #define RTTST_RTDM_DEFER_CLOSE_CONTEXT 1 +#define RTTST_RTDM_START_STOP_TASK 2 #define RTIOC_TYPE_TESTING RTDM_CLASS_TESTING @@ -141,6 +142,10 @@ struct rttst_swtest_error { #define RTTST_RTIOC_RTDM_DEFER_CLOSE \ _IOW(RTIOC_TYPE_TESTING, 0x40, __u32) + +#define RTTST_RTIOC_RTDM_ACTOR_GET_CPU \ + _IOR(RTIOC_TYPE_TESTING, 0x41, __u32) + /** @} */ #endif /* !_RTDM_UAPI_TESTING_H */ diff --git a/kernel/drivers/testing/rtdmtest.c b/kernel/drivers/testing/rtdmtest.c index c5224d0..5c705e6 100644 --- a/kernel/drivers/testing/rtdmtest.c +++ b/kernel/drivers/testing/rtdmtest.c @@ -17,7 +17,6 @@ */ #include <linux/module.h> - #include <rtdm/driver.h> #include <rtdm/testing.h> @@ -26,28 +25,38 @@ MODULE_AUTHOR("Jan Kiszka <jan.kis...@web.de>"); MODULE_VERSION("0.1.0"); MODULE_LICENSE("GPL"); -struct rtdm_test_context { +struct rtdm_basic_context { rtdm_timer_t close_timer; unsigned long close_counter; unsigned long close_deferral; }; +struct rtdm_actor_context { + rtdm_task_t actor_task; + unsigned int request; + rtdm_event_t run; + rtdm_event_t done; + union { + __u32 cpu; + } args; +}; + static void close_timer_proc(rtdm_timer_t *timer) { - struct rtdm_test_context *ctx = - container_of(timer, struct rtdm_test_context, close_timer); + struct rtdm_basic_context *ctx = + container_of(timer, struct rtdm_basic_context, close_timer); if (ctx->close_counter != 1) - printk(KERN_ERR + printk(XENO_ERR "rtdmtest: %s: close_counter is %lu, should be 1!\n", __FUNCTION__, ctx->close_counter); rtdm_fd_unlock(rtdm_private_to_fd(ctx)); } -static int rtdm_test_open(struct rtdm_fd *fd, int oflags) +static int rtdm_basic_open(struct rtdm_fd *fd, int oflags) { - struct rtdm_test_context *ctx = rtdm_fd_to_private(fd); + struct rtdm_basic_context *ctx = rtdm_fd_to_private(fd); rtdm_timer_init(&ctx->close_timer, close_timer_proc, "rtdm close test"); @@ -57,16 +66,16 @@ static int rtdm_test_open(struct rtdm_fd *fd, int oflags) return 0; } -static void rtdm_test_close(struct rtdm_fd *fd) +static void rtdm_basic_close(struct rtdm_fd *fd) { - struct rtdm_test_context *ctx = rtdm_fd_to_private(fd); + struct rtdm_basic_context *ctx = rtdm_fd_to_private(fd); ctx->close_counter++; switch (ctx->close_deferral) { case RTTST_RTDM_DEFER_CLOSE_CONTEXT: if (ctx->close_counter != 2) { - printk(KERN_ERR + printk(XENO_ERR "rtdmtest: %s: close_counter is %lu, " "should be 2!\n", __FUNCTION__, ctx->close_counter); @@ -78,10 +87,10 @@ static void rtdm_test_close(struct rtdm_fd *fd) rtdm_timer_destroy(&ctx->close_timer); } -static int -rtdm_test_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) +static int rtdm_basic_ioctl(struct rtdm_fd *fd, + unsigned int request, void __user *arg) { - struct rtdm_test_context *ctx = rtdm_fd_to_private(fd); + struct rtdm_basic_context *ctx = rtdm_fd_to_private(fd); int err = 0; switch (request) { @@ -94,7 +103,6 @@ rtdm_test_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) RTDM_TIMERMODE_RELATIVE); } break; - default: err = -ENOTTY; } @@ -102,30 +110,137 @@ rtdm_test_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) return err; } -static struct rtdm_driver rtdmtest_driver = { - .profile_info = RTDM_PROFILE_INFO(rtdmtest, +static void actor_handler(void *arg) +{ + struct rtdm_actor_context *ctx = arg; + int ret; + + for (;;) { + if (rtdm_task_should_stop()) + return; + + ret = rtdm_event_wait(&ctx->run); + if (ret) + break; + + switch (ctx->request) { + case RTTST_RTIOC_RTDM_ACTOR_GET_CPU: + ctx->args.cpu = task_cpu(current); + break; + default: + printk(XENO_ERR "rtdmtest: bad request code %d\n", + ctx->request); + } + + rtdm_event_signal(&ctx->done); + } +} + +static int rtdm_actor_open(struct rtdm_fd *fd, int oflags) +{ + struct rtdm_actor_context *ctx = rtdm_fd_to_private(fd); + + rtdm_event_init(&ctx->run, 0); + rtdm_event_init(&ctx->done, 0); + + return rtdm_task_init(&ctx->actor_task, "rtdm_actor", + actor_handler, ctx, + RTDM_TASK_LOWEST_PRIORITY, 0); +} + +static void rtdm_actor_close(struct rtdm_fd *fd) +{ + struct rtdm_actor_context *ctx = rtdm_fd_to_private(fd); + + rtdm_task_destroy(&ctx->actor_task); + rtdm_event_destroy(&ctx->run); + rtdm_event_destroy(&ctx->done); +} + +#define ACTION_TIMEOUT 50000000ULL /* 50 ms timeout on action */ + +static int run_action(struct rtdm_actor_context *ctx, unsigned int request) +{ + rtdm_toseq_t toseq; + + rtdm_toseq_init(&toseq, ACTION_TIMEOUT); + ctx->request = request; + rtdm_event_signal(&ctx->run); + /* + * XXX: The handshake mechanism is not bullet-proof against + * -EINTR received when waiting for the done event. Hopefully + * we won't restart/start a request while the action task has + * not yet completed the previous one we stopped waiting for + * abruptly. + */ + return rtdm_event_timedwait(&ctx->done, ACTION_TIMEOUT, &toseq); +} + +static int rtdm_actor_ioctl(struct rtdm_fd *fd, + unsigned int request, void __user *arg) +{ + struct rtdm_actor_context *ctx = rtdm_fd_to_private(fd); + int ret; + + switch (request) { + case RTTST_RTIOC_RTDM_ACTOR_GET_CPU: + ctx->args.cpu = (__u32)-EINVAL; + ret = run_action(ctx, request); + if (ret) + break; + ret = rtdm_safe_copy_to_user(fd, arg, &ctx->args.cpu, + sizeof(ctx->args.cpu)); + break; + default: + ret = -ENOTTY; + } + + return ret; +} + +static struct rtdm_driver rtdm_basic_driver = { + .profile_info = RTDM_PROFILE_INFO(rtdm_test_basic, RTDM_CLASS_TESTING, RTDM_SUBCLASS_RTDMTEST, RTTST_PROFILE_VER), .device_flags = RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE, .device_count = 2, - .context_size = sizeof(struct rtdm_test_context), + .context_size = sizeof(struct rtdm_basic_context), + .ops = { + .open = rtdm_basic_open, + .close = rtdm_basic_close, + .ioctl_rt = rtdm_basic_ioctl, + .ioctl_nrt = rtdm_basic_ioctl, + }, +}; + +static struct rtdm_driver rtdm_actor_driver = { + .profile_info = RTDM_PROFILE_INFO(rtdm_test_actor, + RTDM_CLASS_TESTING, + RTDM_SUBCLASS_RTDMTEST, + RTTST_PROFILE_VER), + .device_flags = RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE, + .device_count = 1, + .context_size = sizeof(struct rtdm_actor_context), .ops = { - .open = rtdm_test_open, - .close = rtdm_test_close, - .ioctl_rt = rtdm_test_ioctl, - .ioctl_nrt = rtdm_test_ioctl, + .open = rtdm_actor_open, + .close = rtdm_actor_close, + .ioctl_rt = rtdm_actor_ioctl, }, }; -static struct rtdm_device device[2] = { +static struct rtdm_device device[3] = { [0 ... 1] = { - .driver = &rtdmtest_driver, + .driver = &rtdm_basic_driver, .label = "rtdm%d", + }, + [2] = { + .driver = &rtdm_actor_driver, + .label = "rtdmx", } }; -static int __init __rtdm_test_init(void) +static int __init rtdm_test_init(void) { int i, ret; @@ -146,7 +261,7 @@ fail: return ret; } -static void __exit __rtdm_test_exit(void) +static void __exit rtdm_test_exit(void) { int i; @@ -154,5 +269,5 @@ static void __exit __rtdm_test_exit(void) rtdm_dev_unregister(device + i); } -module_init(__rtdm_test_init); -module_exit(__rtdm_test_exit); +module_init(rtdm_test_init); +module_exit(rtdm_test_exit); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://xenomai.org/mailman/listinfo/xenomai-git