From: Pavel Machek <pma@domain.hid>
To: Jan Kiszka <jan.kiszka@domain.hid>
Cc: xenomai@xenomai.org
Subject: Re: [Xenomai-help] kernel oopses when killing realtime task
Date: Fri, 8 Oct 2010 09:01:48 +0200 [thread overview]
Message-ID: <20101008070148.GB2255@domain.hid> (raw)
In-Reply-To: <4CADBDC2.8080600@domain.hid>
Hi!
> > I have... quite an interesting setup here.
> >
> > SMP machine, with special PCI card; that card has GPIOs and serial
> > ports. Unfortunately, there's only one interrupt, shared between
> > serials and GPIO pins, and serials are way too complex to be handled
> > by realtime layer.
> >
> > So I ended up with
> >
> > // we also have an interrupt handler:
> > ret = rtdm_irq_request(&my_context->irq_handle,
> > gpio_rt_config.irq, demo_interrupt,
> > RTDM_IRQTYPE_SHARED,
> > context->device->proc_name, my_context);
> >
> > and
> >
> > static int demo_interrupt(rtdm_irq_t *irq_context)
> > {
> > struct demodrv_context *ctx;
> > int dev_id;
> > int ret = RTDM_IRQ_HANDLED; // usual return value
> > unsigned pending, output;
> >
> > ctx = rtdm_irq_get_arg(irq_context, struct demodrv_context);
> > dev_id = ctx->dev_id;
> >
> > if (!ctx->ready) {
> > printk(KERN_CRIT "Unexpected interrupt\n");
> > return XN_ISR_PROPAGATE;
>
> Who sets ready and when? Looks racy.
Debugging aid; yes, this one is racy.
> > rtdm_lock_put(&ctx->lock);
> >
> > /* We need to propagate the interrupt, so that PMC-6L serials
> > work. Result is that interrupt latencies can't be
> > guaranteed when serials are in use. */
> >
> > return RTDM_IRQ_HANDLED;
> > }
> >
> > Unregistration is:
> > my_context->ready = 0;
> > rtdm_irq_disable(&my_context->irq_handle);
>
> Where is rtdm_irq_free? Again, this ready flag looks racy.
Aha, sorry, I quoted wrong snippet. rtdm_irq_free() follows
immediately, like this:
int demo_close_rt(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info)
{
struct demodrv_context *my_context;
rtdm_lockctx_t lock_ctx;
// get the context
my_context = (struct demodrv_context *)context->dev_private;
// if we need to do some stuff with preemption disabled:
rtdm_lock_get_irqsave(&my_context->lock, lock_ctx);
my_context->ready = 0;
rtdm_irq_disable(&my_context->irq_handle);
// free irq in RTDM
rtdm_irq_free(&my_context->irq_handle);
// destroy our interrupt signal/event
rtdm_event_destroy(&my_context->irq_event);
// other stuff here
rtdm_lock_put_irqrestore(&my_context->lock, lock_ctx);
return 0;
}
Now... I'm aware that lock_get/put around irq_free should be
unneccessary, as should be irq_disable and my ->ready flag. Those were
my attempts to work around the problem. I'll attach the full source at
the end.
> > Unfortunately, when the userspace app is ran and killed repeatedly (so
> > that interrupt is registered/unregistered all the time), I get
> > oopses in __ipipe_dispatch_wired() -- it seems to call into the NULL
> > pointer.
> >
> > I decided that "wired" interrupt when the source is shared between
> > Linux and Xenomai, is wrong thing, so I disable "wired" interrupts
> > altogether, but that only moved oops to __virq_end.
>
> This is wrong. The only way to get a determistically shared IRQs across
> domains is via the wired path, either using the pattern Gilles cited or,
> in a slight variation, signaling down via a separate rtdm_nrtsig.
For now, I'm trying to get it not to oops; deterministic latencies are
the next topic :-(.
The hardware is little unusual that it generates interrupts at 1kHz,
whether realtime driver is loaded or not.
Pavel
/**********************************************************/
/* HARD REAL TIME RTDM Driver Skeleton V1.1 */
/* */
/* Based on code of Jan Kiszka - thanks Jan! */
/* (C) 2006 Jan Kiszka, www.captain.at */
/* (C) 2010 Pavel Machek, sysgo */
/* License: GPL */
/**********************************************************/
/* Note: Interrupt is shared between serial lines and GPIOs. That
means that interrupt latencies can't be guaranteed when serials are
in use.
*/
#include <linux/mman.h>
#include <rtdm/rtdm_driver.h>
#include "pmc6l-rt.h"
char dummy_buffer[BUFSIZE];
int events;
// our driver context struct: used for storing various information
struct demodrv_context {
rtdm_irq_t irq_handle;
rtdm_lock_t lock;
int dev_id;
u64 last_timestamp;
rtdm_event_t irq_event;
volatile unsigned long irq_event_lock;
volatile int irq_events;
int64_t timeout;
void *buf;
int ready;
};
#define GPIO_CONF_LOW 0xb0
#define GPIO_CONF_HIGH 0xb2
#define GPIO_STATUS_IN 0xb4
#define GPIO_STATUS_OUT 0xb6
#define GPIO_IRQ_ID 0x2a
#define iowrite(bits, val, adr) iowrite##bits(cpu_to_be##bits(val), adr)
#define ioread(bits, adr) be##bits##_to_cpu(ioread##bits(adr))
#define pgwrite(dat, adr) iowrite(16, (dat), gpio_rt_config.mmio+(adr))
#define pgread(adr) ioread(16, gpio_rt_config.mmio+(adr))
/**********************************************************/
/* INTERRUPT HANDLING */
/**********************************************************/
/*
* Demo interrupt code; when GPIO #2 is changed, GPIO #4 is toggled.
*/
static int demo_interrupt(rtdm_irq_t *irq_context)
{
struct demodrv_context *ctx;
int dev_id;
int ret = RTDM_IRQ_HANDLED; // usual return value
unsigned pending, output;
ctx = rtdm_irq_get_arg(irq_context, struct demodrv_context);
dev_id = ctx->dev_id;
if (!ctx->ready) {
printk(KERN_CRIT "Unexpected interrupt\n");
return XN_ISR_PROPAGATE;
}
#if 0
rtdm_lock_get(&ctx->lock);
pending = pgread(GPIO_IRQ_ID);
pgwrite(0, GPIO_IRQ_ID);
output = pgread(GPIO_STATUS_OUT);
output ^= (1<<3);
pgwrite(output, GPIO_STATUS_OUT);
// do stuff
if (events > 1000) {
rtdm_event_signal(&ctx->irq_event);
events = 0;
}
events++;
rtdm_lock_put(&ctx->lock);
// those return values were dropped from the RTDM
// ret = RTDM_IRQ_ENABLE | RTDM_IRQ_PROPAGATE;
/* We need to propagate the interrupt, so that PMC-6L serials
work. Result is that interrupt latencies can't be
guaranteed when serials are in use. */
// return XN_ISR_PROPAGATE;
return RTDM_IRQ_HANDLED;
#else
pending = pgread(GPIO_IRQ_ID);
pgwrite(0, GPIO_IRQ_ID);
output = pgread(GPIO_STATUS_OUT);
output = output & (~(1<<3));
if (pgread(GPIO_STATUS_IN) & (1<<1))
output |= (1<<3);
pgwrite(output, GPIO_STATUS_OUT);
// those return values were dropped from the RTDM
// ret = RTDM_IRQ_ENABLE | RTDM_IRQ_PROPAGATE;
/* We need to propagate the interrupt, so that PMC-6L serials
work. Result is that interrupt latencies can't be
guaranteed when serials are in use. */
// return XN_ISR_PROPAGATE;
return RTDM_IRQ_HANDLED;
#endif
}
/**********************************************************/
/* DRIVER OPEN */
/**********************************************************/
int demo_open_rt(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info,
int oflags)
{
struct demodrv_context *my_context;
int dev_id = context->device->device_id;
int ret;
// get the context for our driver - used to store driver info
my_context = (struct demodrv_context *)context->dev_private;
// we also have an interrupt handler:
ret = rtdm_irq_request(&my_context->irq_handle, gpio_rt_config.irq, demo_interrupt,
RTDM_IRQTYPE_SHARED, context->device->proc_name, my_context);
if (ret < 0)
return ret;
/* IPC initialisation - cannot fail with used parameters */
rtdm_lock_init(&my_context->lock);
rtdm_event_init(&my_context->irq_event, 0);
my_context->dev_id = dev_id;
my_context->irq_events = 0;
my_context->irq_event_lock = 0;
my_context->ready = 1;
my_context->timeout = 0; // wait INFINITE
// enable interrupt in RTDM
rtdm_irq_enable(&my_context->irq_handle);
return 0;
}
/**********************************************************/
/* DRIVER CLOSE */
/**********************************************************/
int demo_close_rt(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info)
{
struct demodrv_context *my_context;
rtdm_lockctx_t lock_ctx;
// get the context
my_context = (struct demodrv_context *)context->dev_private;
// if we need to do some stuff with preemption disabled:
rtdm_lock_get_irqsave(&my_context->lock, lock_ctx);
my_context->ready = 0;
rtdm_irq_disable(&my_context->irq_handle);
// free irq in RTDM
rtdm_irq_free(&my_context->irq_handle);
// destroy our interrupt signal/event
rtdm_event_destroy(&my_context->irq_event);
// other stuff here
rtdm_lock_put_irqrestore(&my_context->lock, lock_ctx);
return 0;
}
/**********************************************************/
/* DRIVER READ */
/**********************************************************/
int demo_read_rt(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info, void *buf, size_t nbyte)
{
struct demodrv_context *ctx;
int dev_id;
char *out_pos = (char *)buf;
rtdm_toseq_t timeout_seq;
int ret;
// zero bytes requested ? return!
if (nbyte == 0)
return 0;
// check if R/W actions to user-space are allowed
if (user_info && !rtdm_rw_user_ok(user_info, buf, nbyte))
return -EFAULT;
ctx = (struct demodrv_context *)context->dev_private;
dev_id = ctx->dev_id;
// wait: if ctx->timeout = 0, it will block infintely until
// rtdm_event_signal(&ctx->irq_event); is called from our
// interrupt routine
ret = rtdm_event_timedwait(&ctx->irq_event, ctx->timeout, &timeout_seq);
// now write the requested stuff to user-space
if (rtdm_copy_to_user(user_info, out_pos,
dummy_buffer, BUFSIZE) != 0) {
ret = -EFAULT;
} else {
ret = BUFSIZE;
}
return ret;
}
/**********************************************************/
/* DRIVER OPERATIONS */
/**********************************************************/
static struct rtdm_device demo_device = {
struct_version: RTDM_DEVICE_STRUCT_VER,
device_flags: RTDM_NAMED_DEVICE,
context_size: sizeof(struct demodrv_context),
device_name: DEV_FILE,
/* open and close functions are not real-time safe due kmalloc
and kfree. If you do not use kmalloc and kfree, and you made
sure that there is no syscall in the open/close handler, you
can declare the open_rt and close_rt handler.
*/
open_rt: NULL,
open_nrt: demo_open_rt,
ops: {
close_rt: NULL,
close_nrt: demo_close_rt,
ioctl_rt: NULL,
ioctl_nrt: NULL,
read_rt: demo_read_rt,
read_nrt: NULL,
write_rt: NULL,
write_nrt: NULL,
recvmsg_rt: NULL,
recvmsg_nrt: NULL,
sendmsg_rt: NULL,
sendmsg_nrt: NULL,
},
device_class: RTDM_CLASS_EXPERIMENTAL,
device_sub_class: 222,
driver_name: DRV_NAME,
peripheral_name: DEV_FILE_NAME,
provider_name: "-",
proc_name: demo_device.device_name,
};
/**********************************************************/
/* INIT DRIVER */
/**********************************************************/
int init_module(void)
{
pmc_gpio_rt_config();
printk("realtime driver at irq %d mmio %x\n",
gpio_rt_config.irq, gpio_rt_config.mmio);
return rtdm_dev_register(&demo_device);
}
/**********************************************************/
/* CLEANUP DRIVER */
/**********************************************************/
void cleanup_module(void)
{
rtdm_dev_unregister(&demo_device, 1000);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM Real Time Driver Example");
--- user app ----
/**********************************************************/
/* HARD REAL TIME RTDM Driver User-Space Application */
/* */
/* Based on code of Jan Kiszka - thanks Jan! */
/* (C) 2006 Jan Kiszka, www.captain.at */
/* (C) 2010 Pavel Machek, sysgo */
/* License: GPL */
/**********************************************************/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <native/task.h>
#include <native/timer.h>
#include <rtdm/rtdm.h>
#include "pmc6l-rt.h"
unsigned int my_state = 0;
int timer_started = 0;
int my_fd = -1;
int shutdownnow = 0;
RT_TASK my_task;
// --s-ms-us-ns
RTIME my_task_period_ns = 1000000000llu;
/**********************************************************/
/* CLOSE RT DRIVER */
/**********************************************************/
static int close_file( int fd, unsigned char *name) {
int ret,i=0;
do {
i++;
ret = rt_dev_close(fd);
switch(-ret){
case EBADF: printf("%s -> invalid fd or context\n",name);
break;
case EAGAIN: printf("%s -> EAGAIN (%d times)\n",name,i);
rt_task_sleep(50000); // wait 50us
break;
case 0: printf("%s -> closed\n",name);
break;
default: printf("%s -> ???\n",name);
break;
}
} while (ret == -EAGAIN && i < 10);
return ret;
}
/**********************************************************/
/* CLEANING UP */
/**********************************************************/
void cleanup_all(void) {
if (my_state & STATE_FILE_OPENED) {
close_file( my_fd, DEV_FILE " (user)");
my_state &= ~STATE_FILE_OPENED;
}
if (my_state & STATE_TASK_CREATED) {
printf("delete my_task\n");
rt_task_delete(&my_task);
my_state &= ~STATE_TASK_CREATED;
}
if (timer_started) {
printf("stop timer\n");
rt_timer_stop();
}
}
void catch_signal(int sig) {
shutdownnow = 1;
cleanup_all();
printf("exit\n");
return;
}
/**********************************************************/
/* REAL TIME TASK */
/**********************************************************/
void my_task_proc(void *arg) {
int ret;
ssize_t sz = sizeof(RTIME);
ssize_t written = 0;
ssize_t read = 0;
int counter = 0;
int readbackcounter;
unsigned char buf[17] = "CAPTAIN WAS HERE\0";
unsigned char buf2[17] = "XXXXXXXXXXXXXXXX\0";
/* no periodic task, due blocking read from the RT driver (see below too)
ret = rt_task_set_periodic(NULL, TM_NOW, rt_timer_ns2ticks(my_task_period_ns));
if (ret) {
printf("error while set periodic, code %d\n",ret);
goto exit_my_task;
}
*/
while (1) {
sprintf(buf, "CAPTAIN %d", counter);
counter++;
if (counter > 100) counter = 0;
/* switch to primary mode */
ret = rt_task_set_mode(0, T_PRIMARY, NULL);
if (ret) {
printf("error while rt_task_set_mode, code %d\n",ret);
goto exit_my_task;
}
sz = sizeof(buf2);
read = rt_dev_read(my_fd, &buf2, sizeof(buf2));
if (read == sz ) {
printf("READ: read=%s\n",buf2);
} else {
if (read < 0 ) {
printf("error while rt_dev_read, code %d\n",read);
} else {
printf("only %d / %d byte received \n",read,sz);
}
}
// read blocks, so check if user hit CTRL-C meanwhile
// otherwise we segfault when mmap'ing
if (shutdownnow == 1) break;
}
exit_my_task:
if (my_state & STATE_FILE_OPENED) {
if (!close_file( my_fd, DEV_FILE " (write)")) {
my_state &= ~STATE_FILE_OPENED;
}
}
printf("exit\n");
}
/**********************************************************/
/* MAIN: mainly RT task initialization */
/**********************************************************/
int main(int argc, char* argv[]) {
int ret = 0;
signal(SIGTERM, catch_signal);
signal(SIGINT, catch_signal);
printf("PRESS CTRL-C to EXIT\n");
/* no memory-swapping for this programm */
mlockall(MCL_CURRENT | MCL_FUTURE);
/* start timer */
ret = rt_timer_start(TM_ONESHOT);
switch (ret) {
case 0: printf("timer started\n");
timer_started = 1;
break;
case -EBUSY: printf("timer is running\n");
timer_started = 0;
break;
case -ENOSYS: printf("can't start timer\n");
return ret;
}
/* open DEV_FILE */
my_fd = rt_dev_open( DEV_FILE, 0);
if (my_fd < 0) {
printf("can't open %s\n", DEV_FILE);
goto error;
}
my_state |= STATE_FILE_OPENED;
printf("%s opened\n", DEV_FILE);
/* create my_task */
ret = rt_task_create(&my_task,"my_task",0,50,0);
if (ret) {
printf("failed to create my_task, code %d\n",ret);
goto error;
}
my_state |= STATE_TASK_CREATED;
printf("my_task created\n");
/* start my_task */
printf("starting my_task\n");
ret = rt_task_start(&my_task,&my_task_proc,NULL);
if (ret) {
printf("failed to start my_task, code %d\n",ret);
goto error;
}
pause();
return 0;
error:
cleanup_all();
return ret;
}
next prev parent reply other threads:[~2010-10-08 7:01 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-07 11:57 [Xenomai-help] kernel oopses when killing realtime task Pavel Machek
2010-10-07 12:11 ` Gilles Chanteperdrix
2010-10-07 13:00 ` Gilles Chanteperdrix
2010-10-07 12:32 ` Jan Kiszka
2010-10-08 7:01 ` Pavel Machek [this message]
2010-10-08 7:20 ` Gilles Chanteperdrix
2010-10-08 8:17 ` Philippe Gerum
2010-10-08 8:41 ` Jan Kiszka
2010-10-08 8:57 ` Philippe Gerum
2010-10-08 9:00 ` Philippe Gerum
2010-10-08 9:41 ` Philippe Gerum
2010-10-13 9:03 ` Pavel Machek
2010-10-13 9:16 ` Philippe Gerum
2010-10-13 9:26 ` Pavel Machek
2010-10-13 14:52 ` Philippe Gerum
2010-10-25 16:48 ` Philippe Gerum
2010-10-25 18:10 ` Jan Kiszka
2010-10-25 19:08 ` Philippe Gerum
2010-10-25 19:11 ` Philippe Gerum
2010-10-25 19:15 ` Jan Kiszka
2010-10-25 19:20 ` Philippe Gerum
2010-10-25 19:22 ` Jan Kiszka
2010-10-25 21:12 ` Philippe Gerum
2010-10-25 21:22 ` Jan Kiszka
2010-10-25 21:40 ` Philippe Gerum
2010-10-25 21:47 ` Jan Kiszka
2010-10-26 4:43 ` Philippe Gerum
2010-10-26 5:22 ` Jan Kiszka
2010-10-26 19:33 ` Jan Kiszka
2010-10-28 5:17 ` Philippe Gerum
2010-10-28 7:31 ` Jan Kiszka
2010-10-28 7:38 ` Jan Kiszka
2010-10-28 7:46 ` Philippe Gerum
2010-11-07 15:15 ` Philippe Gerum
2010-11-07 16:22 ` Jan Kiszka
2010-11-07 16:55 ` Philippe Gerum
2010-11-07 16:59 ` Philippe Gerum
2010-11-07 17:19 ` Philippe Gerum
2010-11-09 8:01 ` Jan Kiszka
2010-11-09 8:26 ` Philippe Gerum
2010-11-09 8:39 ` Jan Kiszka
2010-11-09 9:36 ` Philippe Gerum
2010-11-09 13:12 ` Jan Kiszka
2010-11-12 8:48 ` Philippe Gerum
2010-11-12 9:14 ` Jan Kiszka
2010-11-12 13:57 ` Philippe Gerum
2010-11-12 14:30 ` Jan Kiszka
2010-11-12 17:42 ` Philippe Gerum
2010-11-12 18:42 ` Jan Kiszka
2010-11-14 21:28 ` Philippe Gerum
2010-10-07 14:07 ` Philippe Gerum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20101008070148.GB2255@domain.hid \
--to=pma@domain.hid \
--cc=jan.kiszka@domain.hid \
--cc=xenomai@xenomai.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.