lkml.org 
[lkml]   [1999]   [May]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Subject2.2.7 Alpha Semaphore Bug
Date
Hi,

I'm having more problems with semaphores on a LX164 Alpha with 2.2.7.

I have one part of the kernel talking to a kernel thread using semaphores.
Every time a process wants the thread to do work, it puts the work on a queue
and does an up() that wakes up the thread. If there are multiple pieces of
work to do, up() may be called multiple times before the thread gets scheduled.

Eventually, the thread gets scheduled and starts to do work. For each piece
of work, the thread does a down() on the semaphore to see if there is more
work or if the thread should sleep.

The problem is that the thread doesn't sleep when the counter of the semaphore
reaches zero. The counter of the semaphore goes negative and the thread
keeps going. If the up() function was called on the semaphore 5 times,
the thread eventually goes to sleep when the counter reaches -5.

Here's my test case (a module) and its output:

#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
char kernel_version [] = UTS_RELEASE;

#include <linux/locks.h>
#include <linux/smp_lock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>


struct mydata
{
struct semaphore comm_sema, work_sema;
struct task_struct *thread;
};



static int gfs_inoded(void *data)
{
struct mydata *md = (struct mydata *)data;


printk("thread: In the thread\n");

/* Set up the thread */

lock_kernel();

exit_mm(current);

current->session = 1;
current->pgrp = 1;

siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
current->fs->umask = 0;

sprintf(current->comm, "gfs_inoded");

md->thread = current;

unlock_kernel();


/* Wake up the process who started us */

up(&md->comm_sema);


while (1)
{
printk("thread: before down_interruptible(): counter = %d\n", md->work_sema.count.counter);
down_interruptible(&md->work_sema);
printk("thread: after down_interruptible(): counter = %d\n", md->work_sema.count.counter);

if (signal_pending(current))
{
printk("thread: Thread received signal\n");
break;
}

printk("thread: Doing work...\n");
}

md->thread = NULL;

up(&md->comm_sema);

printk("thread: Leaving the thread\n");

return(0);
}


int init_module(void)
{
struct mydata md;
int x;


printk("init: Started init_module...\n");

md.comm_sema = MUTEX_LOCKED;
md.work_sema = MUTEX_LOCKED;


for (x = 0; x < 5; x++)
{
printk("init: before up(): count = %d\n", md.work_sema.count.counter);
up(&md.work_sema);
printk("init: after up(): count = %d\n", md.work_sema.count.counter);
}


printk("init: Starting thread...\n");

if (kernel_thread(gfs_inoded, &md, 0) < 0)
return(-EIO);

printk("init: Thread started. Waiting for semaphore...\n");

down(&md.comm_sema);

printk("init: The thread is up\n");


printk("init: Sending signal to stop thread\n");

send_sig(SIGKILL, md.thread, 1);

down(&md.comm_sema);


printk("init: exiting...\n");

return(-EIO);
}


Compiled on a i686 with "cc -D__KERNEL__ -DMODULE -Wall -O2 -c test.c",
it does the right thing:

init: Started init_module...
init: before up(): count = 0
init: after up(): count = 1
init: before up(): count = 1
init: after up(): count = 2
init: before up(): count = 2
init: after up(): count = 3
init: before up(): count = 3
init: after up(): count = 4
init: before up(): count = 4
init: after up(): count = 5
init: Starting thread...
thread: In the thread
thread: before down_interruptible(): counter = 5
thread: after down_interruptible(): counter = 4
thread: Doing work...
thread: before down_interruptible(): counter = 4
thread: after down_interruptible(): counter = 3
thread: Doing work...
thread: before down_interruptible(): counter = 3
thread: after down_interruptible(): counter = 2
thread: Doing work...
thread: before down_interruptible(): counter = 2
thread: after down_interruptible(): counter = 1
thread: Doing work...
thread: before down_interruptible(): counter = 1
thread: after down_interruptible(): counter = 0
thread: Doing work...
thread: before down_interruptible(): counter = 0
init: Thread started. Waiting for semaphore...
init: The thread is up
init: Sending signal to stop thread
thread: after down_interruptible(): counter = 0
thread: Thread received signal
thread: Leaving the thread
init: exiting...

Compiled on a LX164 Alpha with "cc -D__KERNEL__ -DMODULE -Wall -O2 -mno-fp-regs
-ffixed-8 -Wa,-m21164a -DBWIO_ENABLED -mcpu=ev56 -c test.c", the counter on
the semaphore goes negative.

init: Started init_module...
init: before up(): count = 0
init: after up(): count = 1
init: before up(): count = 1
init: after up(): count = 2
init: before up(): count = 2
init: after up(): count = 3
init: before up(): count = 3
init: after up(): count = 4
init: before up(): count = 4
init: after up(): count = 5
init: Starting thread...
init: Thread started. Waiting for semaphore...
thread: In the thread
thread: before down_interruptible(): counter = 5
thread: after down_interruptible(): counter = 4
thread: Doing work...
thread: before down_interruptible(): counter = 4
thread: after down_interruptible(): counter = 3
thread: Doing work...
thread: before down_interruptible(): counter = 3
thread: after down_interruptible(): counter = 2
thread: Doing work...
thread: before down_interruptible(): counter = 2
thread: after down_interruptible(): counter = 1
thread: Doing work...
thread: before down_interruptible(): counter = 1
thread: after down_interruptible(): counter = 0
thread: Doing work...
thread: before down_interruptible(): counter = 0
thread: after down_interruptible(): counter = -1
thread: Doing work...
thread: before down_interruptible(): counter = -1
thread: after down_interruptible(): counter = -2
thread: Doing work...
thread: before down_interruptible(): counter = -2
thread: after down_interruptible(): counter = -3
thread: Doing work...
thread: before down_interruptible(): counter = -3
thread: after down_interruptible(): counter = -4
thread: Doing work...
thread: before down_interruptible(): counter = -4
thread: after down_interruptible(): counter = -5
thread: Doing work...
thread: before down_interruptible(): counter = -5
init: The thread is up
init: Sending signal to stop thread
thread: after down_interruptible(): counter = -5
thread: Thread received signal
thread: Leaving the thread
init: exiting...


Thanks for your help,

Ken



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:51    [W:0.043 / U:0.536 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site