Skip to content

Commit

Permalink
[MIPS] RTLX: Handle signals when sleeping.
Browse files Browse the repository at this point in the history
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Ralf Baechle committed Feb 26, 2007
1 parent cc39cb1 commit 67e2ccc
Showing 1 changed file with 42 additions and 80 deletions.
122 changes: 42 additions & 80 deletions arch/mips/kernel/rtlx.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ static void stopping(int vpe)

int rtlx_open(int index, int can_sleep)
{
int ret;
struct rtlx_channel *chan;
volatile struct rtlx_info **p;
struct rtlx_channel *chan;
int ret = 0;

if (index >= RTLX_CHANNELS) {
printk(KERN_DEBUG "rtlx_open index out of range\n");
Expand All @@ -165,76 +165,49 @@ int rtlx_open(int index, int can_sleep)
if (rtlx == NULL) {
if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
if (can_sleep) {
DECLARE_WAITQUEUE(wait, current);

/* go to sleep */
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
int ret = 0;

set_current_state(TASK_INTERRUPTIBLE);
while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}

set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);

/* back running */
__wait_event_interruptible(channel_wqs[index].lx_queue,
(p = vpe_get_shared(RTLX_TARG_VPE)),
ret);
if (ret)
goto out_fail;
} else {
printk( KERN_DEBUG "No SP program loaded, and device "
"opened with O_NONBLOCK\n");
channel_wqs[index].in_open = 0;
return -ENOSYS;
ret = -ENOSYS;
goto out_fail;
}
}

if (*p == NULL) {
if (can_sleep) {
DECLARE_WAITQUEUE(wait, current);

/* go to sleep */
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
int ret = 0;

set_current_state(TASK_INTERRUPTIBLE);
while (*p == NULL) {
schedule();

/* reset task state to interruptable otherwise
we'll whizz round here like a very fast loopy
thing. schedule() appears to return with state
set to TASK_RUNNING.
If the loaded SP program, for whatever reason,
doesn't set up the shared structure *p will never
become true. So whoever connected to either /dev/rt?
or if it was kspd, will then take up rather a lot of
processor cycles.
*/

set_current_state(TASK_INTERRUPTIBLE);
}

set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);

/* back running */
}
else {
__wait_event_interruptible(channel_wqs[index].lx_queue,
*p != NULL,
ret);
if (ret)
goto out_fail;
} else {
printk(" *vpe_get_shared is NULL. "
"Has an SP program been loaded?\n");
channel_wqs[index].in_open = 0;
return -ENOSYS;
ret = -ENOSYS;
goto out_fail;
}
}

if ((unsigned int)*p < KSEG0) {
printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
"maybe an error code %d\n", (int)*p);
channel_wqs[index].in_open = 0;
return -ENOSYS;
ret = -ENOSYS;
goto out_fail;
}

if ((ret = rtlx_init(*p)) < 0) {
if ((ret = rtlx_init(*p)) < 0) {
channel_wqs[index].in_open = 0;
return ret;
}
Expand All @@ -250,6 +223,11 @@ int rtlx_open(int index, int can_sleep)
chan->lx_state = RTLX_STATE_OPENED;
channel_wqs[index].in_open = 0;
return 0;

out_fail:
channel_wqs[index].in_open--;

return ret;
}

int rtlx_release(int index)
Expand All @@ -270,30 +248,17 @@ unsigned int rtlx_read_poll(int index, int can_sleep)
/* data available to read? */
if (chan->lx_read == chan->lx_write) {
if (can_sleep) {
DECLARE_WAITQUEUE(wait, current);
int ret = 0;

/* go to sleep */
add_wait_queue(&channel_wqs[index].lx_queue, &wait);
__wait_event_interruptible(channel_wqs[index].lx_queue,
chan->lx_read != chan->lx_write || sp_stopping,
ret);
if (ret)
return ret;

set_current_state(TASK_INTERRUPTIBLE);
while (chan->lx_read == chan->lx_write) {
schedule();

set_current_state(TASK_INTERRUPTIBLE);

if (sp_stopping) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
return 0;
}
}

set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);

/* back running */
}
else
if (sp_stopping)
return 0;
} else
return 0;
}

Expand Down Expand Up @@ -454,25 +419,22 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
{
int minor;
struct rtlx_channel *rt;
DECLARE_WAITQUEUE(wait, current);

minor = iminor(file->f_path.dentry->d_inode);
rt = &rtlx->channel[minor];

/* any space left... */
if (!rtlx_write_poll(minor)) {
int ret = 0;

if (file->f_flags & O_NONBLOCK)
return -EAGAIN;

add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
set_current_state(TASK_INTERRUPTIBLE);

while (!rtlx_write_poll(minor))
schedule();

set_current_state(TASK_RUNNING);
remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
__wait_event_interruptible(channel_wqs[minor].rt_queue,
rtlx_write_poll(minor),
ret);
if (ret)
return ret;
}

return rtlx_write(minor, (void *)buffer, count, 1);
Expand Down

0 comments on commit 67e2ccc

Please sign in to comment.