Hi, attached is an experimental patch to allow blocking from non-RT context on RTDM events. Petr Cervenka made me think about this extension which could partially open RTDM drivers also for non-shadowed, i.e. standard Linux tasks.
Why not simply shadowing non-RT waiters? Because this kind of sync support should be cheaper than adding yet another (though low-prio) task to the real-time domain ("should" == I didn't benchmark my believe). And it's more convenient because no shadow setup is required prior to blocking on "dual-use" resources. The patch seems to work (see attached simple test, also try ^C for interruption testing), but requires more refactoring before being applied. This will not happen before release 2.2 anyway. I also want to add non-RT support for rtdm_sem in the final patch (rtdm_mutex makes no sense due to risk of prio inversion). The whole non-RT support will furthermore become optional to avoid code bloating. Given that we then would have more powerful context-agnostic synchronisation services for RTDM drivers, we may even consider registering certain RTDM devices also with standard Linux, thus making them available to Linux users without the need to use librtdm services. Well, I haven't thought about all implications and limitation of such a step, as well as its actual usefulness. It's just an idea so far. Feedback is welcome, specifically about real tests or bugs you may spot in this code. Jan
Index: include/rtdm/rtdm_driver.h =================================================================== --- include/rtdm/rtdm_driver.h (Revision 1112) +++ include/rtdm/rtdm_driver.h (Arbeitskopie) @@ -921,6 +921,7 @@ static inline void rtdm_toseq_init(rtdm_ typedef struct { xnsynch_t synch_base; + struct list_head nrt_wait_queue; } rtdm_event_t; #define RTDM_EVENT_PENDING XNSYNCH_SPARE1 @@ -928,15 +929,18 @@ typedef struct { static inline void rtdm_event_init(rtdm_event_t *event, unsigned long pending) { xnsynch_init(&event->synch_base, XNSYNCH_PRIO); + INIT_LIST_HEAD(&event->nrt_wait_queue); if (pending) xnsynch_set_flags(&event->synch_base, RTDM_EVENT_PENDING); } void _rtdm_synch_flush(xnsynch_t *synch, unsigned long reason); +void _rtdm_nrtev_destroy(struct list_head *wait_queue); static inline void rtdm_event_destroy(rtdm_event_t *event) { _rtdm_synch_flush(&event->synch_base, XNRMID); + _rtdm_nrtev_destroy(&event->nrt_wait_queue); } int rtdm_event_wait(rtdm_event_t *event); @@ -944,10 +948,11 @@ int rtdm_event_timedwait(rtdm_event_t *e rtdm_toseq_t *timeout_seq); void rtdm_event_signal(rtdm_event_t *event); -static inline void rtdm_event_pulse(rtdm_event_t *event) +/*static inline void rtdm_event_pulse(rtdm_event_t *event) { _rtdm_synch_flush(&event->synch_base, 0); -} +}*/ +void rtdm_event_pulse(rtdm_event_t *event); void rtdm_event_clear(rtdm_event_t *event); Index: ksrc/skins/rtdm/drvlib.c =================================================================== --- ksrc/skins/rtdm/drvlib.c (Revision 1112) +++ ksrc/skins/rtdm/drvlib.c (Arbeitskopie) @@ -2,7 +2,7 @@ * @file * Real-Time Driver Model for Xenomai, driver library * - * @note Copyright (C) 2005 Jan Kiszka <[EMAIL PROTECTED]> + * @note Copyright (C) 2005, 2006 Jan Kiszka <[EMAIL PROTECTED]> * @note Copyright (C) 2005 Joerg Langenberg <[EMAIL PROTECTED]> * * Xenomai is free software; you can redistribute it and/or modify it @@ -548,8 +548,9 @@ void rtdm_event_destroy(rtdm_event_t *ev * @brief Signal an event occurrence to currently listening waiters * * This function wakes up all current waiters of the given event, but it does - * not change the event state. Subsequently callers of rtdm_event_wait() or - * rtdm_event_wait_until() will therefore be blocked first. + * not set the event to a signalled state. Subsequent callers of + * rtdm_event_wait() or rtdm_event_wait_until() will therefore be blocked + * first. * * @param[in,out] event Event handle as returned by rtdm_event_init() * @@ -568,6 +569,146 @@ void rtdm_event_pulse(rtdm_event_t *even #endif /* DOXYGEN_CPP */ +rtdm_nrtsig_t nrtevent; +static LIST_HEAD(nrtev_queue); + +struct nrtev_waiter { + xnflags_t flags; + struct task_struct *task; + struct list_head wait_queue; +}; + +/* Append the entire source wait queue to the target one and reset + the source queue. */ +static fastcall void +rtdm_migrate_nrt_queue(struct list_head *dest, struct list_head *source) +{ + struct list_head *src_head, *src_tail; + + + src_head = source->next; + src_tail = source->prev; + INIT_LIST_HEAD(source); + + dest->prev->next = src_head; + src_head->prev = dest->prev; + + dest->prev = src_tail; + src_tail->next = dest; +} + +static int +rtdm_nrtev_wait(struct list_head *wait_queue, int64_t timeout, spl_t s) +{ + struct nrtev_waiter entry; + int err = 0; + + + entry.flags = 0; + entry.task = current; + list_add(&entry.wait_queue, wait_queue); + set_current_state(TASK_INTERRUPTIBLE); + + xnlock_put_irqrestore(&nklock, s); + + if (timeout) { + unsigned long to = MAX_JIFFY_OFFSET; + + if (timeout < MAX_JIFFY_OFFSET * 1000000000LL / HZ) + to = xnarch_uldiv(timeout, 1000000000 / HZ); + + if (!schedule_timeout(to)) + err = -ETIMEDOUT; + } else + schedule(); + + if (signal_pending(current)) + err = -ERESTARTSYS; + else if (testbits(entry.flags, XNRMID)) + err = -EIDRM; + + xnlock_get_irqsave(&nklock, s); + + list_del(&entry.wait_queue); + + return err; +} + +void _rtdm_nrtev_destroy(struct list_head *nrt_wait_queue) +{ + struct nrtev_waiter *entry; + spl_t s; + + + xnlock_get_irqsave(&nklock, s); + + if (!list_empty(&nrtev_queue)) { + list_for_each_entry(entry, nrt_wait_queue, wait_queue) + setbits(entry->flags, XNRMID); + + rtdm_migrate_nrt_queue(&nrtev_queue, nrt_wait_queue); + rtdm_nrtsig_pend(&nrtevent); + } + + xnlock_put_irqrestore(&nklock, s); +} + +EXPORT_SYMBOL(_rtdm_nrtev_destroy); + + +void rtdm_nrtev_handler(rtdm_nrtsig_t nrt_sig) +{ + struct nrtev_waiter *entry; + spl_t s; + + + xnlock_get_irqsave(&nklock, s); + + while (!list_empty(&nrtev_queue)) { + entry = list_entry(nrtev_queue.next, + struct nrtev_waiter, wait_queue); + + list_del(&entry->wait_queue); + INIT_LIST_HEAD(&entry->wait_queue); + + xnlock_put_irqrestore(&nklock, s); + + wake_up_process(entry->task); + + xnlock_get_irqsave(&nklock, s); + } + + xnlock_put_irqrestore(&nklock, s); +} + + +static fastcall void rtdm_event_pulse_internal(rtdm_event_t *event) +{ + if (xnsynch_flush(&event->synch_base, 0)) + xnpod_schedule(); + + if (!list_empty(&event->nrt_wait_queue)) { + rtdm_migrate_nrt_queue(&nrtev_queue, &event->nrt_wait_queue); + rtdm_nrtsig_pend(&nrtevent); + } +} + + +void rtdm_event_pulse(rtdm_event_t *event) +{ + spl_t s; + + + xnlock_get_irqsave(&nklock, s); + + rtdm_event_pulse_internal(event); + + xnlock_put_irqrestore(&nklock, s); +} + +EXPORT_SYMBOL(rtdm_event_pulse); + + /** * @brief Signal an event occurrence * @@ -596,8 +737,7 @@ void rtdm_event_signal(rtdm_event_t *eve xnlock_get_irqsave(&nklock, s); xnsynch_set_flags(&event->synch_base, RTDM_EVENT_PENDING); - if (xnsynch_flush(&event->synch_base, 0)) - xnpod_schedule(); + rtdm_event_pulse_internal(event); xnlock_put_irqrestore(&nklock, s); } @@ -678,50 +818,65 @@ EXPORT_SYMBOL(rtdm_event_wait); int rtdm_event_timedwait(rtdm_event_t *event, int64_t timeout, rtdm_toseq_t *timeout_seq) { + int64_t eff_timeout; xnthread_t *thread; spl_t s; int err = 0; +#if 1 + XENO_ASSERT(RTDM, !xnpod_asynch_p() && !xnpod_locked_p(), return -EPERM;); +#else XENO_ASSERT(RTDM, !xnpod_unblockable_p(), return -EPERM;); +#endif xnlock_get_irqsave(&nklock, s); - if (unlikely(testbits(event->synch_base.status, RTDM_SYNCH_DELETED))) + if (unlikely(xnsynch_test_flags(&event->synch_base, RTDM_SYNCH_DELETED))) err = -EIDRM; + else if (likely(xnsynch_test_flags(&event->synch_base, RTDM_EVENT_PENDING))) xnsynch_clear_flags(&event->synch_base, RTDM_EVENT_PENDING); - else { + + else if (timeout < 0) { /* non-blocking mode */ - if (timeout < 0) { - err = -EWOULDBLOCK; - goto unlock_out; - } + err = -EWOULDBLOCK; + } else { if (timeout_seq && (timeout > 0)) { /* timeout sequence */ - timeout = *timeout_seq - xnpod_get_time(); - if (unlikely(timeout <= 0)) { + eff_timeout = *timeout_seq - xnpod_get_time(); + if (unlikely(eff_timeout <= 0)) { err = -ETIMEDOUT; goto unlock_out; } - xnsynch_sleep_on(&event->synch_base, timeout); } else { /* infinite or relative timeout */ - xnsynch_sleep_on(&event->synch_base, xnpod_ns2ticks(timeout)); + eff_timeout = xnpod_ns2ticks(timeout); } - thread = xnpod_current_thread(); - - if (likely(!xnthread_test_flags(thread, XNTIMEO|XNRMID|XNBREAK))) - xnsynch_clear_flags(&event->synch_base, RTDM_EVENT_PENDING); - else if (xnthread_test_flags(thread, XNTIMEO)) - err = -ETIMEDOUT; - else if (xnthread_test_flags(thread, XNRMID)) - err = -EIDRM; - else /* XNBREAK */ - err = -EINTR; +#if 1 + if (unlikely(xnpod_root_p())) { + err = rtdm_nrtev_wait(&event->nrt_wait_queue, timeout, s); + if (err == 0) + xnsynch_clear_flags(&event->synch_base, RTDM_EVENT_PENDING); + } else +#endif + { + xnsynch_sleep_on(&event->synch_base, eff_timeout); + + thread = xnpod_current_thread(); + + if (likely(!xnthread_test_flags(thread, XNTIMEO|XNRMID|XNBREAK))) + xnsynch_clear_flags(&event->synch_base, RTDM_EVENT_PENDING); + else if (xnthread_test_flags(thread, XNTIMEO)) + err = -ETIMEDOUT; + else if (xnthread_test_flags(thread, XNRMID)) + err = -EIDRM; + else /* XNBREAK */ + err = -EINTR; + } } unlock_out: Index: ksrc/skins/rtdm/module.c =================================================================== --- ksrc/skins/rtdm/module.c (Revision 1112) +++ ksrc/skins/rtdm/module.c (Arbeitskopie) @@ -49,6 +49,7 @@ #endif /* __KERNEL__ */ #include "rtdm/device.h" +#include "rtdm/drvlib.h" #include "rtdm/proc.h" @@ -97,10 +98,14 @@ int SKIN_INIT(rtdm) if (err) goto cleanup_pod; + err = rtdm_nrtev_init(); + if (err) + goto cleanup_dev; + #ifdef CONFIG_PROC_FS err = rtdm_proc_init(); if (err) - goto cleanup_dev; + goto cleanup_nrtev; #endif /* CONFIG_PROC_FS */ #if defined(__KERNEL__) && defined(CONFIG_XENO_OPT_PERVASIVE) @@ -124,9 +129,12 @@ int SKIN_INIT(rtdm) #ifdef CONFIG_PROC_FS rtdm_proc_cleanup(); - cleanup_dev: + cleanup_nrtev: #endif /* CONFIG_PROC_FS */ + rtdm_nrtev_cleanup(); + + cleanup_dev: rtdm_dev_cleanup(); cleanup_pod: Index: ksrc/skins/rtdm/drvlib.h =================================================================== --- ksrc/skins/rtdm/drvlib.h (Revision 0) +++ ksrc/skins/rtdm/drvlib.h (Revision 0) @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Jan Kiszka <[EMAIL PROTECTED]>. + * + * Xenomai is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Xenomai is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xenomai; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _RTDM_DRVLIB_H +#define _RTDM_DRVLIB_H + +#include <rtdm/rtdm_driver.h> + + +extern rtdm_nrtsig_t nrtevent; + +void rtdm_nrtev_handler(rtdm_nrtsig_t nrt_sig); + +static inline int rtdm_nrtev_init(void) +{ + return rtdm_nrtsig_init(&nrtevent, rtdm_nrtev_handler); +} + +static inline void rtdm_nrtev_cleanup(void) +{ + rtdm_nrtsig_destroy(&nrtevent); +} + +#endif /* _RTDM_DRVLIB_H */
#include <linux/module.h> #include <rtdm/rtdm_driver.h> rtdm_task_t task; rtdm_event_t ev; void task_fnc(void *arg) { rtdm_task_sleep(20*1000000000LL); rtdm_event_signal(&ev); printk("signalled\n"); } int nrtev_test(void) { rtdm_event_init(&ev, 0); rtdm_task_init(&task, "nrtev_test", task_fnc, NULL, 20, 0); printk("waiting...\n"); printk("res1 = %d\n", rtdm_event_timedwait(&ev, 5000000000LL, NULL)); printk("res2 = %d\n", rtdm_event_timedwait(&ev, -1, NULL)); printk("res3 = %d\n", rtdm_event_timedwait(&ev, 0, NULL)); rtdm_task_join_nrt(&task, 100); printk("done\n"); return -ENOANO; } module_init(nrtev_test);
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Xenomai-core mailing list Xenomai-core@gna.org https://mail.gna.org/listinfo/xenomai-core