All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-core] [PATCH] rework xnintr locking, enhance proc output
@ 2006-09-26 11:53 Jan Kiszka
  2006-09-27 16:48 ` Philippe Gerum
  0 siblings, 1 reply; 2+ messages in thread
From: Jan Kiszka @ 2006-09-26 11:53 UTC (permalink / raw)
  To: xenomai-core


[-- Attachment #1.1: Type: text/plain, Size: 799 bytes --]

This patch series reworks the locking of xnintr_attach and xnintr_detach
with respect to xnintr_irq_proc. So far the locking during proc output
contains a risk of deadlock when an IRQ was detached concurrently.

The new version also introduces IRQ names for the non-shared case so
that drivers or other IRQ registering instances are always made visible.

The series consists of the functional changes in the first patch
(xnintr-locking-v4.patch) and a code reordering in the second one
(xnintr-reorder-v2.patch). Apply in that order.

Credits definitely go to Dmitry as well who helped a lot with cleaning
up and reordering my first patch version.

Jan

PS: This series also paves the way for upcoming patches to add (almost)
perfectly fair IRQ CPU load statistics. Stay tuned! 8)

[-- Attachment #1.2: xnintr-locking-v4.patch --]
[-- Type: text/plain, Size: 10613 bytes --]

---
 ChangeLog           |    7 +
 ksrc/nucleus/intr.c |  201 +++++++++++++++++++++++++---------------------------
 2 files changed, 104 insertions(+), 104 deletions(-)

Index: xenomai/ksrc/nucleus/intr.c
===================================================================
--- xenomai.orig/ksrc/nucleus/intr.c
+++ xenomai/ksrc/nucleus/intr.c
@@ -3,6 +3,7 @@
  * \author Philippe Gerum
  *
  * Copyright (C) 2001,2002,2003 Philippe Gerum <rpm@xenomai.org>.
+ * Copyright (C) 2005,2006 Dmitry Adamushko <dmitry.adamushko@domain.hid>.
  *
  * Xenomai is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
@@ -35,19 +36,19 @@
 #include <nucleus/ltt.h>
 #include <asm/xenomai/bits/intr.h>
 
+#ifdef CONFIG_SMP
+xnlock_t intrlock;
+#endif /* CONFIG_SMP */
+
 xnintr_t nkclock;
 
 static void xnintr_irq_handler(unsigned irq, void *cookie);
 
-#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-
-/* Helper functions. */
-static int xnintr_shirq_attach(xnintr_t *intr, void *cookie);
-static int xnintr_shirq_detach(xnintr_t *intr);
-
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+static int xnintr_irq_attach(xnintr_t *intr);
+static int xnintr_irq_detach(xnintr_t *intr);
+static void xnintr_synchronize(xnintr_t *intr);
 
-/*! 
+/*!
  * \fn int xnintr_init (xnintr_t *intr,const char *name,unsigned irq,xnisr_t isr,xniack_t iack,xnflags_t flags)
  * \brief Initialize an interrupt object.
  *
@@ -198,7 +199,7 @@ int xnintr_destroy(xnintr_t *intr)
 	return 0;
 }
 
-/*! 
+/*!
  * \fn int xnintr_attach (xnintr_t *intr, void *cookie);
  * \brief Attach an interrupt object.
  *
@@ -234,14 +235,19 @@ int xnintr_destroy(xnintr_t *intr)
 
 int xnintr_attach(xnintr_t *intr, void *cookie)
 {
+	int err;
+	spl_t s;
+
 	intr->hits = 0;
 	intr->cookie = cookie;
-#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-	return xnintr_shirq_attach(intr, cookie);
-#else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
-	return xnarch_hook_irq(intr->irq, &xnintr_irq_handler, intr->iack,
-			       intr);
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+	xnlock_get_irqsave(&intrlock, s);
+
+	err = xnintr_irq_attach(intr);
+
+	xnlock_put_irqrestore(&intrlock, s);
+
+	return err;
 }
 
 /*! 
@@ -275,11 +281,22 @@ int xnintr_attach(xnintr_t *intr, void *
 
 int xnintr_detach(xnintr_t *intr)
 {
-#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-	return xnintr_shirq_detach(intr);
-#else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
-	return xnarch_release_irq(intr->irq);
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+	int err;
+	spl_t s;
+
+	xnlock_get_irqsave(&intrlock, s);
+
+	err = xnintr_irq_detach(intr);
+
+	xnlock_put_irqrestore(&intrlock, s);
+
+	/* The idea here is to keep a detached interrupt object valid as long
+	   as the corresponding irq handler is running. This is one of the
+	   requirements to iterate over the xnintr_shirq_t::handlers list in
+	   xnintr_irq_handler() in a lockless way. */
+	xnintr_synchronize(intr);
+
+	return err;
 }
 
 /*! 
@@ -436,42 +453,37 @@ typedef struct xnintr_shirq {
 	int unhandled;
 #ifdef CONFIG_SMP
 	atomic_counter_t active;
-#endif				/* CONFIG_SMP */
+#endif
 
 } xnintr_shirq_t;
 
 static xnintr_shirq_t xnshirqs[RTHAL_NR_IRQS];
 
-#ifdef CONFIG_SMP
 static inline void xnintr_shirq_lock(xnintr_shirq_t *shirq)
 {
+#ifdef CONFIG_SMP
 	xnarch_atomic_inc(&shirq->active);
+#endif
 }
 
 static inline void xnintr_shirq_unlock(xnintr_shirq_t *shirq)
 {
+#ifdef CONFIG_SMP
 	xnarch_atomic_dec(&shirq->active);
+#endif
 }
 
-static inline void xnintr_shirq_spin(xnintr_shirq_t *shirq)
+void xnintr_synchronize(xnintr_t *intr)
 {
+#ifdef CONFIG_SMP
+	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
+
 	while (xnarch_atomic_get(&shirq->active))
 		cpu_relax();
+#endif
 }
-#else /* !CONFIG_SMP */
-static inline void xnintr_shirq_lock(xnintr_shirq_t *shirq)
-{
-}
-static inline void xnintr_shirq_unlock(xnintr_shirq_t *shirq)
-{
-}
-static inline void xnintr_shirq_spin(xnintr_shirq_t *shirq)
-{
-}
-#endif /* CONFIG_SMP */
 
 #if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL)
-
 /*
  * Low-level interrupt handler dispatching the user-defined ISRs for
  * shared interrupts -- Called with interrupts off.
@@ -524,7 +536,6 @@ static void xnintr_shirq_handler(unsigne
 #endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL */
 
 #if defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-
 /*
  * Low-level interrupt handler dispatching the user-defined ISRs for
  * shared edge-triggered interrupts -- Called with interrupts off.
@@ -597,32 +608,25 @@ static void xnintr_edge_shirq_handler(un
 
 #endif /* CONFIG_XENO_OPT_SHIRQ_EDGE */
 
-static int xnintr_shirq_attach(xnintr_t *intr, void *cookie)
+int xnintr_irq_attach(xnintr_t *intr)
 {
 	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
 	xnintr_t *prev, **p = &shirq->handlers;
-	int err = 0;
-	spl_t s;
+	int err;
 
 	if (intr->irq >= RTHAL_NR_IRQS)
 		return -EINVAL;
 
-	xnlock_get_irqsave(&nklock, s);
-
-	if (__testbits(intr->flags, XN_ISR_ATTACHED)) {
-		err = -EPERM;
-		goto unlock_and_exit;
-	}
+	if (__testbits(intr->flags, XN_ISR_ATTACHED))
+		return -EPERM;
 
 	if ((prev = *p) != NULL) {
 		/* Check on whether the shared mode is allowed. */
 		if (!(prev->flags & intr->flags & XN_ISR_SHARED) ||
 		    (prev->iack != intr->iack)
 		    || ((prev->flags & XN_ISR_EDGE) !=
-			(intr->flags & XN_ISR_EDGE))) {
-			err = -EBUSY;
-			goto unlock_and_exit;
-		}
+			(intr->flags & XN_ISR_EDGE)))
+			return -EBUSY;
 
 		/* Get a position at the end of the list to insert the new element. */
 		while (prev) {
@@ -647,7 +651,7 @@ static int xnintr_shirq_attach(xnintr_t 
 
 		err = xnarch_hook_irq(intr->irq, handler, intr->iack, intr);
 		if (err)
-			goto unlock_and_exit;
+			return err;
 	}
 
 	__setbits(intr->flags, XN_ISR_ATTACHED);
@@ -656,28 +660,20 @@ static int xnintr_shirq_attach(xnintr_t 
 	intr->next = NULL;
 	*p = intr;
 
-      unlock_and_exit:
-
-	xnlock_put_irqrestore(&nklock, s);
-	return err;
+	return 0;
 }
 
-int xnintr_shirq_detach(xnintr_t *intr)
+int xnintr_irq_detach(xnintr_t *intr)
 {
 	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
 	xnintr_t *e, **p = &shirq->handlers;
 	int err = 0;
-	spl_t s;
 
 	if (intr->irq >= RTHAL_NR_IRQS)
 		return -EINVAL;
 
-	xnlock_get_irqsave(&nklock, s);
-
-	if (!__testbits(intr->flags, XN_ISR_ATTACHED)) {
-		xnlock_put_irqrestore(&nklock, s);
+	if (!__testbits(intr->flags, XN_ISR_ATTACHED))
 		return -EPERM;
-	}
 
 	__clrbits(intr->flags, XN_ISR_ATTACHED);
 
@@ -690,23 +686,13 @@ int xnintr_shirq_detach(xnintr_t *intr)
 			if (shirq->handlers == NULL)
 				err = xnarch_release_irq(intr->irq);
 
-			xnlock_put_irqrestore(&nklock, s);
-
-			/* The idea here is to keep a detached interrupt object valid as long
-			   as the corresponding irq handler is running. This is one of the requirements
-			   to iterate over the xnintr_shirq_t::handlers list in xnintr_irq_handler()
-			   in a lockless way. */
-
-			xnintr_shirq_spin(shirq);
 			return err;
 		}
 		p = &e->next;
 	}
 
-	xnlock_put_irqrestore(&nklock, s);
-
-	xnlogerr
-	    ("attempted to detach a non previously attached interrupt object.\n");
+	xnlogerr("attempted to detach a non previously attached interrupt "
+		 "object.\n");
 	return err;
 }
 
@@ -717,16 +703,33 @@ int xnintr_mount(void)
 		xnshirqs[i].handlers = NULL;
 #ifdef CONFIG_SMP
 		atomic_set(&xnshirqs[i].active, 0);
-#endif /* CONFIG_SMP */
+#endif
 	}
 	return 0;
 }
 
+#else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+int xnintr_irq_attach(xnintr_t *intr)
+{
+	return xnarch_hook_irq(intr->irq, &xnintr_irq_handler, intr->iack, intr);
+}
+
+int xnintr_irq_detach(xnintr_t *intr)
+{
+	return xnarch_release_irq(intr->irq);
+}
+
+void xnintr_synchronize(xnintr_t *intr) {}
+int xnintr_mount(void) { return 0; }
+
+#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+
 int xnintr_irq_proc(unsigned int irq, char *str)
 {
-	xnintr_shirq_t *shirq;
 	xnintr_t *intr;
 	char *p = str;
+	spl_t s;
 
 	if (rthal_virtual_irq_p(irq)) {
 		p += sprintf(p, "         [virtual]");
@@ -736,43 +739,33 @@ int xnintr_irq_proc(unsigned int irq, ch
 		return p - str;
 	}
 
-	shirq = &xnshirqs[irq];
+	xnlock_get_irqsave(&intrlock, s);
 
-	xnintr_shirq_lock(shirq);
-	intr = shirq->handlers;
-
-	if (intr)
-		p += sprintf(p, "        ");
-
-	while (intr) {
-		if (*(intr->name))
-			p += sprintf(p, " %s,", intr->name);
+#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
+	intr = xnshirqs[irq].handlers;
+	if (intr) {
+		strcpy(p, "        "); p += 8;
+
+		do {
+			*p = ' '; p += 1;
+			strcpy(p, intr->name); p += strlen(intr->name);
 
-		intr = intr->next;
+			intr = intr->next;
+		} while (intr);
 	}
-
-	xnintr_shirq_unlock(shirq);
-
-	if (p != str)
-		--p;
-
-	return p - str;
-}
-
 #else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
+	intr = rthal_irq_cookie(&rthal_domain, irq);
+	if (intr) {
+		strcpy(p, "         "); p += 9;
+		strcpy(p, intr->name); p += strlen(intr->name);
+	}
+#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
 
-int xnintr_mount(void)
-{
-	return 0;
-}
+	xnlock_put_irqrestore(&intrlock, s);
 
-int xnintr_irq_proc(unsigned int irq, char *str)
-{
-	return 0;
+	return p - str;
 }
 
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
-
 EXPORT_SYMBOL(xnintr_attach);
 EXPORT_SYMBOL(xnintr_destroy);
 EXPORT_SYMBOL(xnintr_detach);
Index: xenomai/ChangeLog
===================================================================
--- xenomai.orig/ChangeLog
+++ xenomai/ChangeLog
@@ -1,3 +1,10 @@
+2006-09-26  Jan Kiszka  <jan.kiszka@domain.hid>
+            Dmitry Adamushko  <dmitry.adamushko@domain.hid>
+
+	* ksrc/nucleus/intr.c: Reorganise locking around xnintr_attach,
+	and xnintr_detach in order to avoid races with xnintr_irq_proc,
+	provide IRQ owner names also for non-shared setups, refactor code.
+
 2006-09-25  Niklaus Giger <niklaus.giger@domain.hid>
 
 	* ksrc/arch/powerpc/hal.c (rthal_set_cpu_timers_unsafe): Fix

[-- Attachment #1.3: xnintr-reorder-v2.patch --]
[-- Type: text/plain, Size: 30115 bytes --]

---
 ksrc/nucleus/intr.c |  883 +++++++++++++++++++++++++---------------------------
 1 file changed, 439 insertions(+), 444 deletions(-)

Index: xenomai/ksrc/nucleus/intr.c
===================================================================
--- xenomai.orig/ksrc/nucleus/intr.c
+++ xenomai/ksrc/nucleus/intr.c
@@ -36,363 +36,14 @@
 #include <nucleus/ltt.h>
 #include <asm/xenomai/bits/intr.h>
 
+#define XNINTR_MAX_UNHANDLED	1000
+
 #ifdef CONFIG_SMP
 xnlock_t intrlock;
 #endif /* CONFIG_SMP */
 
 xnintr_t nkclock;
 
-static void xnintr_irq_handler(unsigned irq, void *cookie);
-
-static int xnintr_irq_attach(xnintr_t *intr);
-static int xnintr_irq_detach(xnintr_t *intr);
-static void xnintr_synchronize(xnintr_t *intr);
-
-/*!
- * \fn int xnintr_init (xnintr_t *intr,const char *name,unsigned irq,xnisr_t isr,xniack_t iack,xnflags_t flags)
- * \brief Initialize an interrupt object.
- *
- * Associates an interrupt object with an IRQ line.
- *
- * When an interrupt occurs on the given @a irq line, the ISR is fired
- * in order to deal with the hardware event. The interrupt service
- * code may call any non-suspensive service from the nucleus.
- *
- * Upon receipt of an IRQ, the ISR is immediately called on behalf of
- * the interrupted stack context, the rescheduling procedure is
- * locked, and the interrupt source is masked at hardware level. The
- * status value returned by the ISR is then checked for the following
- * values:
- *
- * - XN_ISR_HANDLED indicates that the interrupt request has been fulfilled
- * by the ISR.
- *
- * - XN_ISR_NONE indicates the opposite to XN_ISR_HANDLED. The ISR must always
- * return this value when it determines that the interrupt request has not been
- * issued by the dedicated hardware device.
- *
- * In addition, one of the following bits may be set by the ISR :
- *
- * NOTE: use these bits with care and only when you do understand their effect
- * on the system.
- * The ISR is not encouraged to use these bits in case it shares the IRQ line
- * with other ISRs in the real-time domain.
- *
- * - XN_ISR_PROPAGATE tells the nucleus to require the real-time control
- * layer to forward the IRQ. For instance, this would cause the Adeos
- * control layer to propagate the interrupt down the interrupt
- * pipeline to other Adeos domains, such as Linux. This is the regular
- * way to share interrupts between the nucleus and the host system.
- *
- * - XN_ISR_NOENABLE causes the nucleus to ask the real-time control
- * layer _not_ to re-enable the IRQ line (read the following section).
- * xnarch_end_irq() must be called to re-enable the IRQ line later.
- *
- * The nucleus re-enables the IRQ line by default. Over some real-time
- * control layers which mask and acknowledge IRQs, this operation is
- * necessary to revalidate the interrupt channel so that more interrupts
- * can be notified.
- *
- * A count of interrupt receipts is tracked into the interrupt
- * descriptor, and reset to zero each time the interrupt object is
- * attached. Since this count could wrap around, it should be used as
- * an indication of interrupt activity only.
- *
- * @param intr The address of a interrupt object descriptor the
- * nucleus will use to store the object-specific data.  This
- * descriptor must always be valid while the object is active
- * therefore it must be allocated in permanent memory.
- *
- * @param name An ASCII string standing for the symbolic name of the
- * interrupt object.
- *
- * @param irq The hardware interrupt channel associated with the
- * interrupt object. This value is architecture-dependent. An
- * interrupt object must then be attached to the hardware interrupt
- * vector using the xnintr_attach() service for the associated IRQs
- * to be directed to this object.
- *
- * @param isr The address of a valid low-level interrupt service
- * routine if this parameter is non-zero. This handler will be called
- * each time the corresponding IRQ is delivered on behalf of an
- * interrupt context.  When called, the ISR is passed the descriptor
- * address of the interrupt object.
- *
- * @param iack The address of an optional interrupt acknowledge
- * routine, aimed at replacing the default one. Only very specific
- * situations actually require to override the default setting for
- * this parameter, like having to acknowledge non-standard PIC
- * hardware. @a iack should return a non-zero value to indicate that
- * the interrupt has been properly acknowledged. If @a iack is NULL,
- * the default routine will be used instead.
- *
- * @param flags A set of creation flags affecting the operation. The
- * valid flags are:
- *
- * - XN_ISR_SHARED enables IRQ-sharing with other interrupt objects.
- *
- * - XN_ISR_EDGE is an additional flag need to be set together with XN_ISR_SHARED
- * to enable IRQ-sharing of edge-triggered interrupts.
- *
- * @return No error condition being defined, 0 is always returned.
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- */
-
-int xnintr_init(xnintr_t *intr,
-		const char *name,
-		unsigned irq, xnisr_t isr, xniack_t iack, xnflags_t flags)
-{
-	intr->irq = irq;
-	intr->isr = isr;
-	intr->iack = iack;
-	intr->cookie = NULL;
-	intr->hits = 0;
-	intr->name = name;
-	intr->flags = flags;
-	intr->unhandled = 0;
-#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-	intr->next = NULL;
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
-
-	return 0;
-}
-
-/*! 
- * \fn int xnintr_destroy (xnintr_t *intr)
- * \brief Destroy an interrupt object.
- *
- * Destroys an interrupt object previously initialized by
- * xnintr_init(). The interrupt object is automatically detached by a
- * call to xnintr_detach(). No more IRQs will be dispatched by this
- * object after this service has returned.
- *
- * @param intr The descriptor address of the interrupt object to
- * destroy.
- *
- * @return 0 is returned on success. Otherwise, -EBUSY is returned if
- * an error occurred while detaching the interrupt (see
- * xnintr_detach()).
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- */
-
-int xnintr_destroy(xnintr_t *intr)
-{
-	xnintr_detach(intr);
-	return 0;
-}
-
-/*!
- * \fn int xnintr_attach (xnintr_t *intr, void *cookie);
- * \brief Attach an interrupt object.
- *
- * Attach an interrupt object previously initialized by
- * xnintr_init(). After this operation is completed, all IRQs received
- * from the corresponding interrupt channel are directed to the
- * object's ISR.
- *
- * @param intr The descriptor address of the interrupt object to
- * attach.
- *
- * @param cookie A user-defined opaque value which is stored into the
- * interrupt object descriptor for further retrieval by the ISR/ISR
- * handlers.
- *
- * @return 0 is returned on success. Otherwise, -EINVAL is returned if
- * a low-level error occurred while attaching the interrupt. -EBUSY is
- * specifically returned if the interrupt object was already attached.
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- *
- * @note Attaching an interrupt resets the tracked number of receipts
- * to zero.
- */
-
-int xnintr_attach(xnintr_t *intr, void *cookie)
-{
-	int err;
-	spl_t s;
-
-	intr->hits = 0;
-	intr->cookie = cookie;
-
-	xnlock_get_irqsave(&intrlock, s);
-
-	err = xnintr_irq_attach(intr);
-
-	xnlock_put_irqrestore(&intrlock, s);
-
-	return err;
-}
-
-/*! 
- * \fn int xnintr_detach (xnintr_t *intr)
- * \brief Detach an interrupt object.
- *
- * Detach an interrupt object previously attached by
- * xnintr_attach(). After this operation is completed, no more IRQs
- * are directed to the object's ISR, but the interrupt object itself
- * remains valid. A detached interrupt object can be attached again by
- * a subsequent call to xnintr_attach().
- *
- * @param intr The descriptor address of the interrupt object to
- * detach.
- *
- * @return 0 is returned on success. Otherwise, -EINVAL is returned if
- * a low-level error occurred while detaching the interrupt. Detaching
- * a non-attached interrupt object leads to a null-effect and returns
- * 0.
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- */
-
-int xnintr_detach(xnintr_t *intr)
-{
-	int err;
-	spl_t s;
-
-	xnlock_get_irqsave(&intrlock, s);
-
-	err = xnintr_irq_detach(intr);
-
-	xnlock_put_irqrestore(&intrlock, s);
-
-	/* The idea here is to keep a detached interrupt object valid as long
-	   as the corresponding irq handler is running. This is one of the
-	   requirements to iterate over the xnintr_shirq_t::handlers list in
-	   xnintr_irq_handler() in a lockless way. */
-	xnintr_synchronize(intr);
-
-	return err;
-}
-
-/*! 
- * \fn int xnintr_enable (xnintr_t *intr)
- * \brief Enable an interrupt object.
- *
- * Enables the hardware interrupt line associated with an interrupt
- * object. Over real-time control layers which mask and acknowledge
- * IRQs, this operation is necessary to revalidate the interrupt
- * channel so that more interrupts can be notified.
-
- * @param intr The descriptor address of the interrupt object to
- * enable.
- *
- * @return 0 is returned on success. Otherwise, -EINVAL is returned if
- * a low-level error occurred while enabling the interrupt.
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- */
-
-int xnintr_enable(xnintr_t *intr)
-{
-	return xnarch_enable_irq(intr->irq);
-}
-
-/*! 
- * \fn int xnintr_disable (xnintr_t *intr)
- * \brief Disable an interrupt object.
- *
- * Disables the hardware interrupt line associated with an interrupt
- * object. This operation invalidates further interrupt requests from
- * the given source until the IRQ line is re-enabled anew.
- *
- * @param intr The descriptor address of the interrupt object to
- * disable.
- *
- * @return 0 is returned on success. Otherwise, -EINVAL is returned if
- * a low-level error occurred while disabling the interrupt.
- *
- * Environments:
- *
- * This service can be called from:
- *
- * - Kernel module initialization/cleanup code
- * - Kernel-based task
- * - User-space task
- *
- * Rescheduling: never.
- */
-
-int xnintr_disable(xnintr_t *intr)
-{
-	return xnarch_disable_irq(intr->irq);
-}
-
-/*! 
- * \fn xnarch_cpumask_t xnintr_affinity (xnintr_t *intr, xnarch_cpumask_t cpumask)
- * \brief Set interrupt's processor affinity.
- *
- * Causes the IRQ associated with the interrupt object @a intr to be
- * received only on processors which bits are set in @a cpumask.
- *
- * @param intr The descriptor address of the interrupt object which
- * affinity is to be changed.
- *
- * @param cpumask The new processor affinity of the interrupt object.
- *
- * @return the previous cpumask on success, or an empty mask on
- * failure.
- *
- * @note Depending on architectures, setting more than one bit in @a
- * cpumask could be meaningless.
- */
-
-xnarch_cpumask_t xnintr_affinity(xnintr_t *intr, xnarch_cpumask_t cpumask)
-{
-	return xnarch_set_irq_affinity(intr->irq, cpumask);
-}
-
-/* Low-level clock irq handler. */
-
-void xnintr_clock_handler(void)
-{
-	xnarch_announce_tick();
-	xnintr_irq_handler(nkclock.irq, &nkclock);
-}
-
-#define XNINTR_MAX_UNHANDLED	1000
 /*
  * Low-level interrupt handler dispatching the ISRs -- Called with
  * interrupts off.
@@ -441,8 +92,14 @@ static void xnintr_irq_handler(unsigned 
 	xnltt_log_event(xeno_ev_iexit, irq);
 }
 
-/*@}*/
-
+/* Low-level clock irq handler. */
+
+void xnintr_clock_handler(void)
+{
+	xnarch_announce_tick();
+	xnintr_irq_handler(nkclock.irq, &nkclock);
+}
+
 /* Optional support for shared interrupts. */
 
 #if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
@@ -603,128 +260,465 @@ static void xnintr_edge_shirq_handler(un
 	if (--sched->inesting == 0 && xnsched_resched_p())
 		xnpod_schedule();
 
-	xnltt_log_event(xeno_ev_iexit, irq);
+	xnltt_log_event(xeno_ev_iexit, irq);
+}
+
+#endif /* CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+static inline int xnintr_irq_attach(xnintr_t *intr)
+{
+	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
+	xnintr_t *prev, **p = &shirq->handlers;
+	int err;
+
+	if (intr->irq >= RTHAL_NR_IRQS)
+		return -EINVAL;
+
+	if (__testbits(intr->flags, XN_ISR_ATTACHED))
+		return -EPERM;
+
+	if ((prev = *p) != NULL) {
+		/* Check on whether the shared mode is allowed. */
+		if (!(prev->flags & intr->flags & XN_ISR_SHARED) ||
+		    (prev->iack != intr->iack)
+		    || ((prev->flags & XN_ISR_EDGE) !=
+			(intr->flags & XN_ISR_EDGE)))
+			return -EBUSY;
+
+		/* Get a position at the end of the list to insert the new element. */
+		while (prev) {
+			p = &prev->next;
+			prev = *p;
+		}
+	} else {
+		/* Initialize the corresponding interrupt channel */
+		void (*handler) (unsigned, void *) = &xnintr_irq_handler;
+
+		if (intr->flags & XN_ISR_SHARED) {
+#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL)
+			handler = &xnintr_shirq_handler;
+#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL */
+
+#if defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
+			if (intr->flags & XN_ISR_EDGE)
+				handler = &xnintr_edge_shirq_handler;
+#endif /* CONFIG_XENO_OPT_SHIRQ_EDGE */
+		}
+		shirq->unhandled = 0;
+
+		err = xnarch_hook_irq(intr->irq, handler, intr->iack, intr);
+		if (err)
+			return err;
+	}
+
+	__setbits(intr->flags, XN_ISR_ATTACHED);
+
+	/* Add a given interrupt object. */
+	intr->next = NULL;
+	*p = intr;
+
+	return 0;
+}
+
+static inline int xnintr_irq_detach(xnintr_t *intr)
+{
+	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
+	xnintr_t *e, **p = &shirq->handlers;
+	int err = 0;
+
+	if (intr->irq >= RTHAL_NR_IRQS)
+		return -EINVAL;
+
+	if (!__testbits(intr->flags, XN_ISR_ATTACHED))
+		return -EPERM;
+
+	__clrbits(intr->flags, XN_ISR_ATTACHED);
+
+	while ((e = *p) != NULL) {
+		if (e == intr) {
+			/* Remove a given interrupt object from the list. */
+			*p = e->next;
+
+			/* Release the IRQ line if this was the last user */
+			if (shirq->handlers == NULL)
+				err = xnarch_release_irq(intr->irq);
+
+			return err;
+		}
+		p = &e->next;
+	}
+
+	xnlogerr("attempted to detach a non previously attached interrupt "
+		 "object.\n");
+	return err;
+}
+
+int xnintr_mount(void)
+{
+	int i;
+	for (i = 0; i < RTHAL_NR_IRQS; ++i) {
+		xnshirqs[i].handlers = NULL;
+#ifdef CONFIG_SMP
+		atomic_set(&xnshirqs[i].active, 0);
+#endif
+	}
+	return 0;
+}
+
+#else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+static inline int xnintr_irq_attach(xnintr_t *intr)
+{
+	return xnarch_hook_irq(intr->irq, &xnintr_irq_handler, intr->iack, intr);
+}
+
+static inline int xnintr_irq_detach(xnintr_t *intr)
+{
+	return xnarch_release_irq(intr->irq);
+}
+
+void xnintr_synchronize(xnintr_t *intr) {}
+int xnintr_mount(void) { return 0; }
+
+#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+/*!
+ * \fn int xnintr_init (xnintr_t *intr,const char *name,unsigned irq,xnisr_t isr,xniack_t iack,xnflags_t flags)
+ * \brief Initialize an interrupt object.
+ *
+ * Associates an interrupt object with an IRQ line.
+ *
+ * When an interrupt occurs on the given @a irq line, the ISR is fired
+ * in order to deal with the hardware event. The interrupt service
+ * code may call any non-suspensive service from the nucleus.
+ *
+ * Upon receipt of an IRQ, the ISR is immediately called on behalf of
+ * the interrupted stack context, the rescheduling procedure is
+ * locked, and the interrupt source is masked at hardware level. The
+ * status value returned by the ISR is then checked for the following
+ * values:
+ *
+ * - XN_ISR_HANDLED indicates that the interrupt request has been fulfilled
+ * by the ISR.
+ *
+ * - XN_ISR_NONE indicates the opposite to XN_ISR_HANDLED. The ISR must always
+ * return this value when it determines that the interrupt request has not been
+ * issued by the dedicated hardware device.
+ *
+ * In addition, one of the following bits may be set by the ISR :
+ *
+ * NOTE: use these bits with care and only when you do understand their effect
+ * on the system.
+ * The ISR is not encouraged to use these bits in case it shares the IRQ line
+ * with other ISRs in the real-time domain.
+ *
+ * - XN_ISR_PROPAGATE tells the nucleus to require the real-time control
+ * layer to forward the IRQ. For instance, this would cause the Adeos
+ * control layer to propagate the interrupt down the interrupt
+ * pipeline to other Adeos domains, such as Linux. This is the regular
+ * way to share interrupts between the nucleus and the host system.
+ *
+ * - XN_ISR_NOENABLE causes the nucleus to ask the real-time control
+ * layer _not_ to re-enable the IRQ line (read the following section).
+ * xnarch_end_irq() must be called to re-enable the IRQ line later.
+ *
+ * The nucleus re-enables the IRQ line by default. Over some real-time
+ * control layers which mask and acknowledge IRQs, this operation is
+ * necessary to revalidate the interrupt channel so that more interrupts
+ * can be notified.
+ *
+ * A count of interrupt receipts is tracked into the interrupt
+ * descriptor, and reset to zero each time the interrupt object is
+ * attached. Since this count could wrap around, it should be used as
+ * an indication of interrupt activity only.
+ *
+ * @param intr The address of a interrupt object descriptor the
+ * nucleus will use to store the object-specific data.  This
+ * descriptor must always be valid while the object is active
+ * therefore it must be allocated in permanent memory.
+ *
+ * @param name An ASCII string standing for the symbolic name of the
+ * interrupt object.
+ *
+ * @param irq The hardware interrupt channel associated with the
+ * interrupt object. This value is architecture-dependent. An
+ * interrupt object must then be attached to the hardware interrupt
+ * vector using the xnintr_attach() service for the associated IRQs
+ * to be directed to this object.
+ *
+ * @param isr The address of a valid low-level interrupt service
+ * routine if this parameter is non-zero. This handler will be called
+ * each time the corresponding IRQ is delivered on behalf of an
+ * interrupt context.  When called, the ISR is passed the descriptor
+ * address of the interrupt object.
+ *
+ * @param iack The address of an optional interrupt acknowledge
+ * routine, aimed at replacing the default one. Only very specific
+ * situations actually require to override the default setting for
+ * this parameter, like having to acknowledge non-standard PIC
+ * hardware. @a iack should return a non-zero value to indicate that
+ * the interrupt has been properly acknowledged. If @a iack is NULL,
+ * the default routine will be used instead.
+ *
+ * @param flags A set of creation flags affecting the operation. The
+ * valid flags are:
+ *
+ * - XN_ISR_SHARED enables IRQ-sharing with other interrupt objects.
+ *
+ * - XN_ISR_EDGE is an additional flag need to be set together with XN_ISR_SHARED
+ * to enable IRQ-sharing of edge-triggered interrupts.
+ *
+ * @return No error condition being defined, 0 is always returned.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ */
+
+int xnintr_init(xnintr_t *intr,
+		const char *name,
+		unsigned irq, xnisr_t isr, xniack_t iack, xnflags_t flags)
+{
+	intr->irq = irq;
+	intr->isr = isr;
+	intr->iack = iack;
+	intr->cookie = NULL;
+	intr->hits = 0;
+	intr->name = name;
+	intr->flags = flags;
+	intr->unhandled = 0;
+#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL) || defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
+	intr->next = NULL;
+#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+
+	return 0;
+}
+
+/*!
+ * \fn int xnintr_destroy (xnintr_t *intr)
+ * \brief Destroy an interrupt object.
+ *
+ * Destroys an interrupt object previously initialized by
+ * xnintr_init(). The interrupt object is automatically detached by a
+ * call to xnintr_detach(). No more IRQs will be dispatched by this
+ * object after this service has returned.
+ *
+ * @param intr The descriptor address of the interrupt object to
+ * destroy.
+ *
+ * @return 0 is returned on success. Otherwise, -EBUSY is returned if
+ * an error occurred while detaching the interrupt (see
+ * xnintr_detach()).
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ */
+
+int xnintr_destroy(xnintr_t *intr)
+{
+	xnintr_detach(intr);
+	return 0;
 }
 
-#endif /* CONFIG_XENO_OPT_SHIRQ_EDGE */
+/*!
+ * \fn int xnintr_attach (xnintr_t *intr, void *cookie);
+ * \brief Attach an interrupt object.
+ *
+ * Attach an interrupt object previously initialized by
+ * xnintr_init(). After this operation is completed, all IRQs received
+ * from the corresponding interrupt channel are directed to the
+ * object's ISR.
+ *
+ * @param intr The descriptor address of the interrupt object to
+ * attach.
+ *
+ * @param cookie A user-defined opaque value which is stored into the
+ * interrupt object descriptor for further retrieval by the ISR/ISR
+ * handlers.
+ *
+ * @return 0 is returned on success. Otherwise, -EINVAL is returned if
+ * a low-level error occurred while attaching the interrupt. -EBUSY is
+ * specifically returned if the interrupt object was already attached.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ *
+ * @note Attaching an interrupt resets the tracked number of receipts
+ * to zero.
+ */
 
-int xnintr_irq_attach(xnintr_t *intr)
+int xnintr_attach(xnintr_t *intr, void *cookie)
 {
-	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
-	xnintr_t *prev, **p = &shirq->handlers;
 	int err;
+	spl_t s;
 
-	if (intr->irq >= RTHAL_NR_IRQS)
-		return -EINVAL;
-
-	if (__testbits(intr->flags, XN_ISR_ATTACHED))
-		return -EPERM;
-
-	if ((prev = *p) != NULL) {
-		/* Check on whether the shared mode is allowed. */
-		if (!(prev->flags & intr->flags & XN_ISR_SHARED) ||
-		    (prev->iack != intr->iack)
-		    || ((prev->flags & XN_ISR_EDGE) !=
-			(intr->flags & XN_ISR_EDGE)))
-			return -EBUSY;
-
-		/* Get a position at the end of the list to insert the new element. */
-		while (prev) {
-			p = &prev->next;
-			prev = *p;
-		}
-	} else {
-		/* Initialize the corresponding interrupt channel */
-		void (*handler) (unsigned, void *) = &xnintr_irq_handler;
-
-		if (intr->flags & XN_ISR_SHARED) {
-#if defined(CONFIG_XENO_OPT_SHIRQ_LEVEL)
-			handler = &xnintr_shirq_handler;
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL */
-
-#if defined(CONFIG_XENO_OPT_SHIRQ_EDGE)
-			if (intr->flags & XN_ISR_EDGE)
-				handler = &xnintr_edge_shirq_handler;
-#endif /* CONFIG_XENO_OPT_SHIRQ_EDGE */
-		}
-		shirq->unhandled = 0;
+	intr->hits = 0;
+	intr->cookie = cookie;
 
-		err = xnarch_hook_irq(intr->irq, handler, intr->iack, intr);
-		if (err)
-			return err;
-	}
+	xnlock_get_irqsave(&intrlock, s);
 
-	__setbits(intr->flags, XN_ISR_ATTACHED);
+	err = xnintr_irq_attach(intr);
 
-	/* Add a given interrupt object. */
-	intr->next = NULL;
-	*p = intr;
+	xnlock_put_irqrestore(&intrlock, s);
 
-	return 0;
+	return err;
 }
 
-int xnintr_irq_detach(xnintr_t *intr)
-{
-	xnintr_shirq_t *shirq = &xnshirqs[intr->irq];
-	xnintr_t *e, **p = &shirq->handlers;
-	int err = 0;
-
-	if (intr->irq >= RTHAL_NR_IRQS)
-		return -EINVAL;
+/*!
+ * \fn int xnintr_detach (xnintr_t *intr)
+ * \brief Detach an interrupt object.
+ *
+ * Detach an interrupt object previously attached by
+ * xnintr_attach(). After this operation is completed, no more IRQs
+ * are directed to the object's ISR, but the interrupt object itself
+ * remains valid. A detached interrupt object can be attached again by
+ * a subsequent call to xnintr_attach().
+ *
+ * @param intr The descriptor address of the interrupt object to
+ * detach.
+ *
+ * @return 0 is returned on success. Otherwise, -EINVAL is returned if
+ * a low-level error occurred while detaching the interrupt. Detaching
+ * a non-attached interrupt object leads to a null-effect and returns
+ * 0.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ */
 
-	if (!__testbits(intr->flags, XN_ISR_ATTACHED))
-		return -EPERM;
+int xnintr_detach(xnintr_t *intr)
+{
+	int err;
+	spl_t s;
 
-	__clrbits(intr->flags, XN_ISR_ATTACHED);
+	xnlock_get_irqsave(&intrlock, s);
 
-	while ((e = *p) != NULL) {
-		if (e == intr) {
-			/* Remove a given interrupt object from the list. */
-			*p = e->next;
+	err = xnintr_irq_detach(intr);
 
-			/* Release the IRQ line if this was the last user */
-			if (shirq->handlers == NULL)
-				err = xnarch_release_irq(intr->irq);
+	xnlock_put_irqrestore(&intrlock, s);
 
-			return err;
-		}
-		p = &e->next;
-	}
+	/* The idea here is to keep a detached interrupt object valid as long
+	   as the corresponding irq handler is running. This is one of the
+	   requirements to iterate over the xnintr_shirq_t::handlers list in
+	   xnintr_irq_handler() in a lockless way. */
+	xnintr_synchronize(intr);
 
-	xnlogerr("attempted to detach a non previously attached interrupt "
-		 "object.\n");
 	return err;
 }
 
-int xnintr_mount(void)
-{
-	int i;
-	for (i = 0; i < RTHAL_NR_IRQS; ++i) {
-		xnshirqs[i].handlers = NULL;
-#ifdef CONFIG_SMP
-		atomic_set(&xnshirqs[i].active, 0);
-#endif
-	}
-	return 0;
-}
+/*!
+ * \fn int xnintr_enable (xnintr_t *intr)
+ * \brief Enable an interrupt object.
+ *
+ * Enables the hardware interrupt line associated with an interrupt
+ * object. Over real-time control layers which mask and acknowledge
+ * IRQs, this operation is necessary to revalidate the interrupt
+ * channel so that more interrupts can be notified.
 
-#else /* !CONFIG_XENO_OPT_SHIRQ_LEVEL && !CONFIG_XENO_OPT_SHIRQ_EDGE */
+ * @param intr The descriptor address of the interrupt object to
+ * enable.
+ *
+ * @return 0 is returned on success. Otherwise, -EINVAL is returned if
+ * a low-level error occurred while enabling the interrupt.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ */
 
-int xnintr_irq_attach(xnintr_t *intr)
+int xnintr_enable(xnintr_t *intr)
 {
-	return xnarch_hook_irq(intr->irq, &xnintr_irq_handler, intr->iack, intr);
+	return xnarch_enable_irq(intr->irq);
 }
 
-int xnintr_irq_detach(xnintr_t *intr)
+/*!
+ * \fn int xnintr_disable (xnintr_t *intr)
+ * \brief Disable an interrupt object.
+ *
+ * Disables the hardware interrupt line associated with an interrupt
+ * object. This operation invalidates further interrupt requests from
+ * the given source until the IRQ line is re-enabled anew.
+ *
+ * @param intr The descriptor address of the interrupt object to
+ * disable.
+ *
+ * @return 0 is returned on success. Otherwise, -EINVAL is returned if
+ * a low-level error occurred while disabling the interrupt.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - Kernel-based task
+ * - User-space task
+ *
+ * Rescheduling: never.
+ */
+
+int xnintr_disable(xnintr_t *intr)
 {
-	return xnarch_release_irq(intr->irq);
+	return xnarch_disable_irq(intr->irq);
 }
 
-void xnintr_synchronize(xnintr_t *intr) {}
-int xnintr_mount(void) { return 0; }
+/*!
+ * \fn xnarch_cpumask_t xnintr_affinity (xnintr_t *intr, xnarch_cpumask_t cpumask)
+ * \brief Set interrupt's processor affinity.
+ *
+ * Causes the IRQ associated with the interrupt object @a intr to be
+ * received only on processors which bits are set in @a cpumask.
+ *
+ * @param intr The descriptor address of the interrupt object which
+ * affinity is to be changed.
+ *
+ * @param cpumask The new processor affinity of the interrupt object.
+ *
+ * @return the previous cpumask on success, or an empty mask on
+ * failure.
+ *
+ * @note Depending on architectures, setting more than one bit in @a
+ * cpumask could be meaningless.
+ */
 
-#endif /* CONFIG_XENO_OPT_SHIRQ_LEVEL || CONFIG_XENO_OPT_SHIRQ_EDGE */
+xnarch_cpumask_t xnintr_affinity(xnintr_t *intr, xnarch_cpumask_t cpumask)
+{
+	return xnarch_set_irq_affinity(intr->irq, cpumask);
+}
 
+#ifdef CONFIG_PROC_FS
 int xnintr_irq_proc(unsigned int irq, char *str)
 {
 	xnintr_t *intr;
@@ -765,6 +759,7 @@ int xnintr_irq_proc(unsigned int irq, ch
 
 	return p - str;
 }
+#endif /* CONFIG_PROC_FS */
 
 EXPORT_SYMBOL(xnintr_attach);
 EXPORT_SYMBOL(xnintr_destroy);

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-09-27 16:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-26 11:53 [Xenomai-core] [PATCH] rework xnintr locking, enhance proc output Jan Kiszka
2006-09-27 16:48 ` Philippe Gerum

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.