All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch] udevd - cleanup and better timeout handling
@ 2004-01-25 20:03 Kay Sievers
  2004-01-26 18:22 ` Greg KH
                   ` (30 more replies)
  0 siblings, 31 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-25 20:03 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 1423 bytes --]

Here is the next revision for udevd:
  o Small cleanups all over the place.
  o Swich to the usual linked list format "list.h".
  o Better timeout handling.
      We store a timestamp in in every queued event, so we don't wait longer
      than the timeout specified, if the hole in the list is not shrinking.
  o ignore udevd target if klibc is used

The code is getting better, but we have still major flaws:

  1. We are much too slow.
     We want to exec the  real udev in the background, but a 'remove'
     is much much faster than a 'add', so we have a problem.
     Question: is it neccessary to order events for different devpath's?
     If no, we may wait_pid() for the exec only if we have another udev
     working on the same devpath.

  2. Which sequence is the first one?
     The automatic exit of the daemon, if we have nothing to do, has the
     disadvantage of not knowing if the first incoming seqnum is really
     the first one.
     So we need to delay the exec of the first exec a small amount of time,
     to see if we get one with a smaller seqnum  to exec before.
     Or we simply never exit the daemon, and delay only the very first exec
     after the start of the daemon.
     Which way to go?

  3. Switch away from ancient ipc to sockets?
     We may want threads for this, but klibc doesn't support it.
     Nevermind, the ipc stuff is also not supported :)
     Any idea?

thanks,
Kay

[-- Attachment #2: 01-udevd.patch --]
[-- Type: text/plain, Size: 11477 bytes --]

diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sun Jan 25 20:57:21 2004
+++ b/Makefile	Sun Jan 25 20:57:21 2004
@@ -147,17 +147,19 @@
 		-D__KLIBC__ -fno-builtin-printf
 	LIB_OBJS =
 	LDFLAGS = --static --nostdlib -nostartfiles -nodefaultlibs
+	UDEVD =
 else
 	CRT0 =
 	LIBC = 
 	CFLAGS += -I$(GCCINCDIR)
 	LIB_OBJS = -lc
 	LDFLAGS =
+	UDEVD = $(DAEMON) $(SENDER)
 endif
 
 CFLAGS += -I$(PWD)/libsysfs
 
-all: $(ROOT) $(DAEMON) $(SENDER)
+all: $(ROOT) $(UDEVD)
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
@@ -231,11 +233,11 @@
 	$(LD) $(LDFLAGS) -o $(ROOT) $(CRT0) $(OBJS) $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $(ROOT)
 
-$(DAEMON): $(ROOT) udevd.h udevd.o
+$(DAEMON): udevd.h udevd.o udevd.o logging.o
 	$(LD) $(LDFLAGS) -o $(DAEMON) $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $(ROOT)
 
-$(SENDER): $(ROOT) udevd.h udevsend.o
+$(SENDER): udevd.h udevsend.o udevd.o logging.o
 	$(LD) $(LDFLAGS) -o $(SENDER) $(CRT0) udevsend.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $(ROOT)
 
diff -Nru a/udevd.c b/udevd.c
--- a/udevd.c	Sun Jan 25 20:57:21 2004
+++ b/udevd.c	Sun Jan 25 20:57:21 2004
@@ -22,6 +22,7 @@
  *
  */
 
+#include <stddef.h>
 #include <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/wait.h>
@@ -32,29 +33,38 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <fcntl.h>
 
+#include "list.h"
 #include "udev.h"
 #include "udevd.h"
 #include "logging.h"
 
 #define BUFFER_SIZE			1024
-#define EVENT_TIMEOUT_SECONDS		10
-#define DAEMON_TIMEOUT_SECONDS		30
-
 
 static int expect_seqnum = 0;
-static struct hotplug_msg *head = NULL;
+static int lock_file = -1;
+static char *lock_filename = ".udevd_lock";
 
+LIST_HEAD(msg_list);
 
-static void sig_alarmhandler(int signum)
+static void sig_handler(int signum)
 {
 	dbg("caught signal %d", signum);
 	switch (signum) {
 	case SIGALRM:
 		dbg("event timeout reached");
 		break;
-
+	case SIGINT:
+	case SIGTERM:
+	case SIGKILL:
+		if (lock_file >= 0) {
+			close(lock_file);
+			unlink(lock_filename);
+		}
+		exit(20 + signum);
+		break;
 	default:
 		dbg("unhandled signal");
 	}
@@ -62,41 +72,32 @@
 
 static void dump_queue(void)
 {
-	struct hotplug_msg *p;
-	p = head;
+	struct hotplug_msg *msg;
 
-	dbg("next expected sequence is %d", expect_seqnum);
-	while(p != NULL) {
-		dbg("sequence %d in queue", p->seqnum);
-		p = p->next;
-	}
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static void dump_msg(struct hotplug_msg *pmsg)
+static void dump_msg(struct hotplug_msg *msg)
 {
 	dbg("sequence %d, '%s', '%s', '%s'",
-	    pmsg->seqnum, pmsg->action, pmsg->devpath, pmsg->subsystem);
+	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static int dispatch_msg(struct hotplug_msg *pmsg)
+static int dispatch_msg(struct hotplug_msg *msg)
 {
 	pid_t pid;
-	char *argv[3];
-	extern char **environ;
 
-	dump_msg(pmsg);
+	dump_msg(msg);
 
-	setenv("ACTION", pmsg->action, 1);
-	setenv("DEVPATH", pmsg->devpath, 1);
-	argv[0] = DEFAULT_UDEV_EXEC;
-	argv[1] = pmsg->subsystem;
-	argv[2] = NULL;
+	setenv("ACTION", msg->action, 1);
+	setenv("DEVPATH", msg->devpath, 1);
 
 	pid = fork();
 	switch (pid) {
 	case 0:
 		/* child */
-		execve(argv[0], argv, environ);
+		execl(UDEV_EXEC, "udev", msg->subsystem, NULL);
 		dbg("exec of child failed");
 		exit(1);
 		break;
@@ -104,108 +105,119 @@
 		dbg("fork of child failed");
 		return -1;
 	default:
-		wait(0);
+		wait(NULL);
 	}
 	return 0;
 }
 
-static void set_timer(int seconds)
+static void set_timeout(int seconds)
 {
-	signal(SIGALRM, sig_alarmhandler);
 	alarm(seconds);
+	dbg("set timeout in %d seconds", seconds);
 }
 
 static void check_queue(void)
 {
-	struct hotplug_msg *p;
-	p = head;
-
-	dump_queue();
-	while(head != NULL && head->seqnum == expect_seqnum) {
-		dispatch_msg(head);
+	struct hotplug_msg *msg;
+	struct hotplug_msg *tmp_msg;
+	time_t msg_age;
+
+recheck:
+	/* dispatch events until one is missing */
+	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
+		if (msg->seqnum != expect_seqnum)
+			break;
+		dispatch_msg(msg);
 		expect_seqnum++;
-		p = head;
-		head = head->next;
-		free(p);
+		list_del_init(&msg->list);
+		free(msg);
+	}
+
+	/* recalculate timeout */
+	if (list_empty(&msg_list) == 0) {
+		msg_age = time(NULL) - msg->queue_time;
+		if (msg_age > EVENT_TIMEOUT_SECONDS-1) {
+			info("event %d, age %li seconds, skip event %d-%d",
+			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
+			expect_seqnum = msg->seqnum;
+			goto recheck;
+		}
+		set_timeout(EVENT_TIMEOUT_SECONDS - msg_age);
+		return;
 	}
-	if (head != NULL)
-		set_timer(EVENT_TIMEOUT_SECONDS);
-	else
-		set_timer(DAEMON_TIMEOUT_SECONDS);
+
+	/* queue is empty */
+	set_timeout(UDEVD_TIMEOUT_SECONDS);
 }
 
-static void add_queue(struct hotplug_msg *pmsg)
+static int queue_msg(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *pnewmsg;
-	struct hotplug_msg *p;
-	struct hotplug_msg *p1;
-
-	p = head;
-	p1 = NULL;
-	pnewmsg = malloc(sizeof(struct hotplug_msg));
-	*pnewmsg = *pmsg;
-	pnewmsg->next = NULL;
-	while(p != NULL && pmsg->seqnum > p->seqnum) {
-		p1 = p;
-		p = p->next;
-	}
-	pnewmsg->next = p;
-	if (p1 == NULL) {
-		head = pnewmsg;
-	} else {
-		p1->next = pnewmsg;
+	struct hotplug_msg *new_msg;
+	struct hotplug_msg *tmp_msg;
+
+	new_msg = malloc(sizeof(*new_msg));
+	if (new_msg == NULL) {
+		dbg("error malloc");
+		return -ENOMEM;
 	}
-	dump_queue();
-}
+	memcpy(new_msg, msg, sizeof(*new_msg));
 
-static int lock_file = -1;
-static char *lock_filename = ".udevd_lock";
+	/* store timestamp of queuing */
+	new_msg->queue_time = time(NULL);
+
+	/* sort message by sequence number into list*/
+	list_for_each_entry(tmp_msg, &msg_list, list)
+		if (tmp_msg->seqnum > new_msg->seqnum)
+			break;
+	list_add_tail(&new_msg->list, &tmp_msg->list);
+
+	return 0;
+}
 
-static int process_queue(void)
+static void work(void)
 {
+	struct hotplug_msg *msg;
 	int msgid;
 	key_t key;
-	struct hotplug_msg *pmsg;
 	char buf[BUFFER_SIZE];
 	int ret;
 
-	key = ftok(DEFAULT_UDEVD_EXEC, IPC_KEY_ID);
-	pmsg = (struct hotplug_msg *) buf;
+	key = ftok(UDEVD_EXEC, IPC_KEY_ID);
+	msg = (struct hotplug_msg *) buf;
 	msgid = msgget(key, IPC_CREAT);
 	if (msgid == -1) {
 		dbg("open message queue error");
-		return -1;
+		exit(1);
 	}
 	while (1) {
 		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
 		if (ret != -1) {
-			dbg("current sequence %d, expected sequence %d", pmsg->seqnum, expect_seqnum);
-
-			/* init expected sequence with value from first call */
+			/* init the expected sequence with value from first call */
 			if (expect_seqnum == 0) {
-				expect_seqnum = pmsg->seqnum;
+				expect_seqnum = msg->seqnum;
 				dbg("init next expected sequence number to %d", expect_seqnum);
 			}
-
-			if (pmsg->seqnum > expect_seqnum) {
-				add_queue(pmsg);
-				set_timer(EVENT_TIMEOUT_SECONDS);
-			} else {
-				if (pmsg->seqnum == expect_seqnum) {
-					dispatch_msg(pmsg);
-					expect_seqnum++;
-					check_queue();
-				} else {
-					dbg("timeout event for unexpected sequence number %d", pmsg->seqnum);
-				}
+			dbg("current sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
+			if (msg->seqnum == expect_seqnum) {
+				/* execute expected event */
+				dispatch_msg(msg);
+				expect_seqnum++;
+				check_queue();
+				dump_queue();
+				continue;
 			}
+			if (msg->seqnum > expect_seqnum) {
+				/* something missing, queue event*/
+				queue_msg(msg);
+				check_queue();
+				dump_queue();
+				continue;
+			}
+			dbg("too late for event with sequence %d, even skipped ", msg->seqnum);
 		} else {
 			if (errno == EINTR) {
-				if (head != NULL) {
-					/* event timeout, skip all missing, proceed with next queued event */
-					info("timeout reached, skip events %d - %d", expect_seqnum, head->seqnum-1);
-					expect_seqnum = head->seqnum;
-				} else {
+				/* timeout */
+				if (list_empty(&msg_list)) {
 					info("we have nothing to do, so daemon exits...");
 					if (lock_file >= 0) {
 						close(lock_file);
@@ -214,31 +226,12 @@
 					exit(0);
 				}
 				check_queue();
-			} else {
-				dbg("ipc message receive error '%s'", strerror(errno));
+				dump_queue();
+				continue;
 			}
+			dbg("ipc message receive error '%s'", strerror(errno));
 		}
 	}
-	return 0;
-}
-
-static void sig_handler(int signum)
-{
-	dbg("caught signal %d", signum);
-	switch (signum) {
-		case SIGINT:
-		case SIGTERM:
-		case SIGKILL:
-			if (lock_file >= 0) {
-				close(lock_file);
-				unlink(lock_filename);
-			}
-			exit(20 + signum);
-			break;
-
-		default:
-			dbg("unhandled signal");
-	}
 }
 
 static int one_and_only(void)
@@ -249,18 +242,18 @@
 
 	/* see if we can open */
 	if (lock_file < 0)
-		return -EINVAL;
+		return -1;
 	
 	/* see if we can lock */
 	if (lockf(lock_file, F_TLOCK, 0) < 0) {
 		close(lock_file);
 		unlink(lock_filename);
-		return -EINVAL;
+		return -1;
 	}
 
 	snprintf(string, sizeof(string), "%d\n", getpid());
 	write(lock_file, string, strlen(string));
-	
+
 	return 0;
 }
 
@@ -274,11 +267,11 @@
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
 	signal(SIGKILL, sig_handler);
+	signal(SIGALRM, sig_handler);
 
 	/* we exit if we have nothing to do, next event will start us again */
-	set_timer(DAEMON_TIMEOUT_SECONDS);
+	set_timeout(UDEVD_TIMEOUT_SECONDS);
 
-	/* main loop */
-	process_queue();
-	return 0;
+	work();
+	exit(0);
 }
diff -Nru a/udevd.h b/udevd.h
--- a/udevd.h	Sun Jan 25 20:57:21 2004
+++ b/udevd.h	Sun Jan 25 20:57:21 2004
@@ -21,17 +21,22 @@
  *
  */
 
-#define DEFAULT_UDEV_EXEC	"./udev"
-#define DEFAULT_UDEVD_EXEC	"./udevd"
+#include "list.h"
 
-#define IPC_KEY_ID		0
-#define HOTPLUGMSGTYPE		44
+#define UDEV_EXEC			"./udev"
+#define UDEVD_EXEC			"./udevd"
+#define UDEVD_TIMEOUT_SECONDS		60
+#define EVENT_TIMEOUT_SECONDS		5
+
+#define IPC_KEY_ID			0
+#define HOTPLUGMSGTYPE			44
 
 
 struct hotplug_msg {
 	long mtype;
-	struct hotplug_msg *next;
+	struct list_head list;
 	int seqnum;
+	time_t queue_time;
 	char action[8];
 	char devpath[128];
 	char subsystem[16];
diff -Nru a/udevsend.c b/udevsend.c
--- a/udevsend.c	Sun Jan 25 20:57:21 2004
+++ b/udevsend.c	Sun Jan 25 20:57:21 2004
@@ -64,6 +64,7 @@
 static int build_hotplugmsg(struct hotplug_msg *msg, char *action,
 			    char *devpath, char *subsystem, int seqnum)
 {
+	memset(msg, 0x00, sizeof(msg));
 	msg->mtype = HOTPLUGMSGTYPE;
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
@@ -85,7 +86,8 @@
 		switch (child_pid) {
 		case 0:
 			/* daemon */
-			execl(DEFAULT_UDEVD_EXEC, NULL);
+			setsid();
+			execl(UDEVD_EXEC, "udevd", NULL);
 			dbg("exec of daemon failed");
 			exit(1);
 		case -1:
@@ -99,7 +101,7 @@
 		dbg("fork of helper failed");
 		return -1;
 	default:
-		wait(0);
+		wait(NULL);
 	}
 	return 0;
 }
@@ -147,7 +149,7 @@
 	seq = atoi(seqnum);
 
 	/* create ipc message queue or get id of our existing one */
-	key = ftok(DEFAULT_UDEVD_EXEC, IPC_KEY_ID);
+	key = ftok(UDEVD_EXEC, IPC_KEY_ID);
 	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
 	msgid = msgget(key, IPC_CREAT);
 	if (msgid == -1) {
@@ -165,7 +167,7 @@
 	/* get state of ipc queue */
 	tspec.tv_sec = 0;
 	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = 20;
+	loop = 30;
 	while (loop--) {
 		retval = msgctl(msgid, IPC_STAT, &msg_queue);
 		if (retval == -1) {

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
@ 2004-01-26 18:22 ` Greg KH
  2004-01-26 19:11 ` Kay Sievers
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-01-26 18:22 UTC (permalink / raw)
  To: linux-hotplug

On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> Here is the next revision for udevd:
>   o Small cleanups all over the place.
>   o Swich to the usual linked list format "list.h".
>   o Better timeout handling.
>       We store a timestamp in in every queued event, so we don't wait longer
>       than the timeout specified, if the hole in the list is not shrinking.
>   o ignore udevd target if klibc is used

Nice, I've applied this.

> The code is getting better, but we have still major flaws:
> 
>   1. We are much too slow.
>      We want to exec the  real udev in the background, but a 'remove'
>      is much much faster than a 'add', so we have a problem.
>      Question: is it neccessary to order events for different devpath's?
>      If no, we may wait_pid() for the exec only if we have another udev
>      working on the same devpath.

But how will we keep track of that?  It's probably easier just to wait
for each one to finish, right?

>   2. Which sequence is the first one?
>      The automatic exit of the daemon, if we have nothing to do, has the
>      disadvantage of not knowing if the first incoming seqnum is really
>      the first one.
>      So we need to delay the exec of the first exec a small amount of time,
>      to see if we get one with a smaller seqnum  to exec before.
>      Or we simply never exit the daemon, and delay only the very first exec
>      after the start of the daemon.
>      Which way to go?

I don't mind never exiting the daemon, and leaving a small startup delay
at the beginning to make sure we have things in the proper order.  That
way the delay is only once.

>   3. Switch away from ancient ipc to sockets?
>      We may want threads for this, but klibc doesn't support it.
>      Nevermind, the ipc stuff is also not supported :)
>      Any idea?

Heh, I can easily add the ipc stuff to klibc.
I'm not a experienced enough userspace programmer to discuss the merits
of either option here.  Anyone else?

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
  2004-01-26 18:22 ` Greg KH
@ 2004-01-26 19:11 ` Kay Sievers
  2004-01-26 19:28 ` Greg KH
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-26 19:11 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> >   1. We are much too slow.
> >      We want to exec the  real udev in the background, but a 'remove'
> >      is much much faster than a 'add', so we have a problem.
> >      Question: is it neccessary to order events for different devpath's?
> >      If no, we may wait_pid() for the exec only if we have another udev
> >      working on the same devpath.
> 
> But how will we keep track of that?  It's probably easier just to wait
> for each one to finish, right?

We leave the message in the queue until we reach the SIGCHLD for this
pid. So we can search the queue if we are already working on this devpath,
and delay the new exec until the former exec comes back.

Is it feasible to run in parallel for different paths, or can you think
of any problem?

> >      We may want threads for this, but klibc doesn't support it.
> >      Nevermind, the ipc stuff is also not supported :)
> >      Any idea?
> 
> Heh, I can easily add the ipc stuff to klibc.
> I'm not a experienced enough userspace programmer to discuss the merits
> of either option here.  Anyone else?

IPC is from the 70's :) It's not refcounted so we may leave messages in the
kernel without any process using it. Sockets are nicer, we easily recognize,
if the daemon isn't running. But we need threads for this to implement it
without doing things like I/O multiplex or use of shared memory, cause
all tasks need to work on the same global queue.

So if we can get threads in klibc, I would prefer to switch to sockets.
IPC isn't really a  option for a todays program, but it works for us and
sockets don't solve any big problem we have.

thanks,
Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
  2004-01-26 18:22 ` Greg KH
  2004-01-26 19:11 ` Kay Sievers
@ 2004-01-26 19:28 ` Greg KH
  2004-01-26 19:42 ` Kay Sievers
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-01-26 19:28 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > >   1. We are much too slow.
> > >      We want to exec the  real udev in the background, but a 'remove'
> > >      is much much faster than a 'add', so we have a problem.
> > >      Question: is it neccessary to order events for different devpath's?
> > >      If no, we may wait_pid() for the exec only if we have another udev
> > >      working on the same devpath.
> > 
> > But how will we keep track of that?  It's probably easier just to wait
> > for each one to finish, right?
> 
> We leave the message in the queue until we reach the SIGCHLD for this
> pid. So we can search the queue if we are already working on this devpath,
> and delay the new exec until the former exec comes back.

Ok, if that isn't too much trouble.

> Is it feasible to run in parallel for different paths, or can you think
> of any problem?

I can't think of any problem with that.

> > >      We may want threads for this, but klibc doesn't support it.
> > >      Nevermind, the ipc stuff is also not supported :)
> > >      Any idea?
> > 
> > Heh, I can easily add the ipc stuff to klibc.
> > I'm not a experienced enough userspace programmer to discuss the merits
> > of either option here.  Anyone else?
> 
> IPC is from the 70's :) It's not refcounted so we may leave messages in the
> kernel without any process using it. Sockets are nicer, we easily recognize,
> if the daemon isn't running. But we need threads for this to implement it
> without doing things like I/O multiplex or use of shared memory, cause
> all tasks need to work on the same global queue.
> 
> So if we can get threads in klibc, I would prefer to switch to sockets.
> IPC isn't really a  option for a todays program, but it works for us and
> sockets don't solve any big problem we have.

Where would we need threads to do this?  In udevsend?  Can't we just
send the message to the socket and forget about it there?

In udevd can't we just read the socket if any data is available?

I really, really want to stay away from threads.

No, I do not think klibc will ever support them, and state machines are
much nicer than multi threaded apps (for the most part.)

If sockets don't really help much, I'll go add support to klibc for
ipc...

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (2 preceding siblings ...)
  2004-01-26 19:28 ` Greg KH
@ 2004-01-26 19:42 ` Kay Sievers
  2004-01-26 22:26 ` Greg KH
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-26 19:42 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > 
> > So if we can get threads in klibc, I would prefer to switch to sockets.
> > IPC isn't really a  option for a todays program, but it works for us and
> > sockets don't solve any big problem we have.
> 
> Where would we need threads to do this?  In udevsend?  Can't we just
> send the message to the socket and forget about it there?

udevd need to be able to talk to multiple senders at the same time.
Otherwise a simple connect from a client blocks the whole process.
You may use select() for this and multiplex the connections, or fork
a child and maintain the queue in shared memory. But that's all not
really nice. I think threads are the nicest option, if you want sockets.


> In udevd can't we just read the socket if any data is available?

No, it blocks, until the client sends, or we need to poll.


> No, I do not think klibc will ever support them, and state machines are
> much nicer than multi threaded apps (for the most part.)

What kind of state machine you are thinking of?
How does it handle multiple client sockets. Do you mean a scheduler?


> If sockets don't really help much, I'll go add support to klibc for ipc...

I'm fine with it.
We cant do it later if we want, when all the other problems are solved :)

thanks,
Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (3 preceding siblings ...)
  2004-01-26 19:42 ` Kay Sievers
@ 2004-01-26 22:26 ` Greg KH
  2004-01-26 22:56 ` Kay Sievers
                   ` (25 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-01-26 22:26 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 08:42:44PM +0100, Kay Sievers wrote:
> On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > 
> > > So if we can get threads in klibc, I would prefer to switch to sockets.
> > > IPC isn't really a  option for a todays program, but it works for us and
> > > sockets don't solve any big problem we have.
> > 
> > Where would we need threads to do this?  In udevsend?  Can't we just
> > send the message to the socket and forget about it there?
> 
> udevd need to be able to talk to multiple senders at the same time.

Hm, we can't use the same socket?  I need to read up on how that all
works...

> Otherwise a simple connect from a client blocks the whole process.
> 
> You may use select() for this and multiplex the connections, or fork
> a child and maintain the queue in shared memory. But that's all not
> really nice. I think threads are the nicest option, if you want sockets.

Ok, I'll trust you here :)

> > In udevd can't we just read the socket if any data is available?
> 
> No, it blocks, until the client sends, or we need to poll.

Even if you accept on a socket that has O_NONBLOCK set on it?

> > No, I do not think klibc will ever support them, and state machines are
> > much nicer than multi threaded apps (for the most part.)
> 
> What kind of state machine you are thinking of?
> How does it handle multiple client sockets. Do you mean a scheduler?

Hm, I don't know what kind of state machine I'm thinking of, usually you
can easily replace a program that has a lot of threads with a single one
using a state machine.  But I've also written stuff that can't be done
that way (accepting serial data from one thread, etc.)

> > If sockets don't really help much, I'll go add support to klibc for ipc...
> 
> I'm fine with it.
> We cant do it later if we want, when all the other problems are solved :)

That sounds fine with me :)

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (4 preceding siblings ...)
  2004-01-26 22:26 ` Greg KH
@ 2004-01-26 22:56 ` Kay Sievers
  2004-01-27  6:56 ` Kay Sievers
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-26 22:56 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 02:26:05PM -0800, Greg KH wrote:
> On Mon, Jan 26, 2004 at 08:42:44PM +0100, Kay Sievers wrote:
> > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > 
> > > > So if we can get threads in klibc, I would prefer to switch to sockets.
> > > > IPC isn't really a  option for a todays program, but it works for us and
> > > > sockets don't solve any big problem we have.
> > > 
> > > Where would we need threads to do this?  In udevsend?  Can't we just
> > > send the message to the socket and forget about it there?
> > 
> > udevd need to be able to talk to multiple senders at the same time.
> 
> Hm, we can't use the same socket?  I need to read up on how that all
> works...

You bind() one and then listen() on it. If one connect() to it, you accept()
and use this file descriptor to communicate and bind and listen on a new one.

So now you have the problem:
You have multiple sockets open and must handle it all at once. You have
the option of nonblocking I/O with stupid polling or better with select()
which notifies you if a socket has data for you.
Or the forking of childs, each child takes the accepted socket and the
parent opens a new one. If we fork for every new connection, we lose the
queue and need shared memory, other ipc, pipes or files...

But the problem is getting more complex if you want to do other thing at
the same time like exec a list of udevs in the background and handle
timeouts...
This is all possible with a single process, but I don't want to debug
such a beast.

All problems magically go away with threads, cause we share the same address
space and let the kernel schedule our tasks.

Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (5 preceding siblings ...)
  2004-01-26 22:56 ` Kay Sievers
@ 2004-01-27  6:56 ` Kay Sievers
  2004-01-27 18:55 ` Greg KH
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-27  6:56 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 11813 bytes --]

On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > >   1. We are much too slow.
> > > >      We want to exec the  real udev in the background, but a 'remove'
> > > >      is much much faster than a 'add', so we have a problem.
> > > >      Question: is it neccessary to order events for different devpath's?
> > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > >      working on the same devpath.
> > > 
> > > But how will we keep track of that?  It's probably easier just to wait
> > > for each one to finish, right?
> > 
> > We leave the message in the queue until we reach the SIGCHLD for this
> > pid. So we can search the queue if we are already working on this devpath,
> > and delay the new exec until the former exec comes back.
> 
> Ok, if that isn't too much trouble.
> 
> > Is it feasible to run in parallel for different paths, or can you think
> > of any problem?
> 
> I can't think of any problem with that.

Here is the next round. We have three queues now. All incoming messages
are queued in msg_list and if nothing is missing we move it to the
running_list and exec in the background.
If the exec comes back, it removes the message from the running_list and
frees the message.

Before we exec, we check the running_list if there is a udev running on
the same device path. If yes, we move the message to the delay_list. If
the former exec comes back, we move the message to the running_list and
exec it.

The very first event is delayed now to catch possible earlier sequences,
every following event is executed without delay if no sequence is missing.

The daemon doesn't exit by itself any longer, cause we don't want to
delay every first exec.

I've put a $(PWD) for now in the Makefile for testing this beast. Only
the local binaries are executed, not the /sbin/udev. We can change it
if we are ready for real testing.

And SIGKILL can't be cought, so I removed it from the handler :)

thanks,
Kay


06:58:36 sig_handler: caught signal 15
06:58:36 main: using ipc queue 0x2d548
06:58:37 message is still in the ipc queue, starting daemon...
06:58:37 work: received sequence 3, expected sequence 0
06:58:37 msg_dump_queue: sequence 3 in queue
06:58:37 set_timeout: set timeout in 1 seconds
06:58:37 main: using ipc queue 0x2d548
06:58:37 main: using ipc queue 0x2d548
06:58:37 work: received sequence 1, expected sequence 1
06:58:37 msg_dump_queue: sequence 1 in queue
06:58:37 msg_dump_queue: sequence 3 in queue
06:58:37 msg_dump: sequence 1, 'add', '/block/sda', 'block'
06:58:37 msg_exec: child [8038] created
06:58:37 running_moveto_queue: move sequence 1 [8038] to running queue '/block/sda'
06:58:37 set_timeout: set timeout in 5 seconds
06:58:37 work: received sequence 2, expected sequence 2
06:58:37 msg_dump_queue: sequence 2 in queue
06:58:37 msg_dump_queue: sequence 3 in queue
06:58:37 msg_dump: sequence 2, 'add', '/block/sdb', 'block'
06:58:37 msg_exec: child [8039] created
06:58:37 running_moveto_queue: move sequence 2 [8039] to running queue '/block/sdb'
06:58:37 msg_dump: sequence 3, 'add', '/block/sdc', 'block'
06:58:37 msg_exec: child [8040] created
06:58:37 running_moveto_queue: move sequence 3 [8040] to running queue '/block/sdc'
06:58:37 main: using ipc queue 0x2d548
06:58:37 main: using ipc queue 0x2d548
06:58:37 work: received sequence 4, expected sequence 4
06:58:37 msg_dump_queue: sequence 4 in queue
06:58:37 msg_dump: sequence 4, 'remove', '/block/sdc', 'block'
06:58:37 msg_exec: delay exec of sequence 4, [8040] already working on '/block/sdc'
06:58:37 delayed_moveto_queue: move event to delayed queue '/block/sdc'
06:58:37 msg_exec: child [8043] created
06:58:37 running_moveto_queue: move sequence 4 [8043] to running queue '/block/sdc'
06:58:37 work: received sequence 5, expected sequence 5
06:58:37 msg_dump_queue: sequence 5 in queue
06:58:37 msg_dump: sequence 5, 'remove', '/block/sdb', 'block'
06:58:37 msg_exec: delay exec of sequence 5, [8039] already working on '/block/sdb'
06:58:37 delayed_moveto_queue: move event to delayed queue '/block/sdb'
06:58:37 msg_exec: child [8044] created
06:58:37 running_moveto_queue: move sequence 5 [8044] to running queue '/block/sdb'
06:58:37 main: using ipc queue 0x2d548
06:58:37 main: using ipc queue 0x2d548
06:58:37 work: received sequence 8, expected sequence 6
06:58:37 msg_dump_queue: sequence 8 in queue
06:58:37 set_timeout: set timeout in 5 seconds
06:58:37 work: received sequence 6, expected sequence 6
06:58:37 msg_dump_queue: sequence 6 in queue
06:58:37 msg_dump_queue: sequence 8 in queue
06:58:37 msg_dump: sequence 6, 'remove', '/block/sda', 'block'
06:58:37 msg_exec: delay exec of sequence 6, [8038] already working on '/block/sda'
06:58:37 delayed_moveto_queue: move event to delayed queue '/block/sda'
06:58:37 msg_exec: child [8047] created
06:58:37 running_moveto_queue: move sequence 6 [8047] to running queue '/block/sda'
06:58:37 set_timeout: set timeout in 5 seconds
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8038
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8039
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8040
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8043
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8044
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:38 sig_handler: caught signal 17
06:58:38 sig_handler: exec finished, pid 8047
06:58:38 set_timeout: set timeout in 4 seconds
06:58:38 msg_dump_queue: sequence 8 in queue
06:58:39 main: using ipc queue 0x2d548
06:58:39 main: using ipc queue 0x2d548
06:58:39 work: received sequence 9, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:39 work: received sequence 11, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 msg_dump_queue: sequence 11 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:39 main: using ipc queue 0x2d548
06:58:39 work: received sequence 10, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 msg_dump_queue: sequence 10 in queue
06:58:39 msg_dump_queue: sequence 11 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:39 main: using ipc queue 0x2d548
06:58:39 work: received sequence 13, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 msg_dump_queue: sequence 10 in queue
06:58:39 msg_dump_queue: sequence 11 in queue
06:58:39 msg_dump_queue: sequence 13 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:39 main: using ipc queue 0x2d548
06:58:39 work: received sequence 14, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 msg_dump_queue: sequence 10 in queue
06:58:39 msg_dump_queue: sequence 11 in queue
06:58:39 msg_dump_queue: sequence 13 in queue
06:58:39 msg_dump_queue: sequence 14 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:39 main: using ipc queue 0x2d548
06:58:39 work: received sequence 15, expected sequence 7
06:58:39 msg_dump_queue: sequence 8 in queue
06:58:39 msg_dump_queue: sequence 9 in queue
06:58:39 msg_dump_queue: sequence 10 in queue
06:58:39 msg_dump_queue: sequence 11 in queue
06:58:39 msg_dump_queue: sequence 13 in queue
06:58:39 msg_dump_queue: sequence 14 in queue
06:58:39 msg_dump_queue: sequence 15 in queue
06:58:39 set_timeout: set timeout in 3 seconds
06:58:41 main: using ipc queue 0x2d548
06:58:41 work: received sequence 12, expected sequence 7
06:58:41 msg_dump_queue: sequence 8 in queue
06:58:41 msg_dump_queue: sequence 9 in queue
06:58:41 msg_dump_queue: sequence 10 in queue
06:58:41 msg_dump_queue: sequence 11 in queue
06:58:41 msg_dump_queue: sequence 12 in queue
06:58:41 msg_dump_queue: sequence 13 in queue
06:58:41 msg_dump_queue: sequence 14 in queue
06:58:41 msg_dump_queue: sequence 15 in queue
06:58:41 set_timeout: set timeout in 1 seconds
06:58:42 sig_handler: caught signal 14
06:58:42 sig_handler: event timeout reached
06:58:42 event 8, age 5 seconds, skip event 7-7
06:58:42 msg_dump: sequence 8, 'add', '/block/sdb', 'block'
06:58:42 msg_exec: child [8057] created
06:58:42 running_moveto_queue: move sequence 8 [8057] to running queue '/block/sdb'
06:58:42 msg_dump: sequence 9, 'add', '/block/sdc', 'block'
06:58:42 msg_exec: child [8058] created
06:58:42 running_moveto_queue: move sequence 9 [8058] to running queue '/block/sdc'
06:58:42 msg_dump: sequence 10, 'remove', '/block/sdc', 'block'
06:58:42 msg_exec: delay exec of sequence 10, [8058] already working on '/block/sdc'
06:58:42 delayed_moveto_queue: move event to delayed queue '/block/sdc'
06:58:42 msg_exec: child [8059] created
06:58:42 running_moveto_queue: move sequence 10 [8059] to running queue '/block/sdc'
06:58:42 msg_dump: sequence 11, 'remove', '/block/sdb', 'block'
06:58:42 msg_exec: delay exec of sequence 11, [8057] already working on '/block/sdb'
06:58:42 delayed_moveto_queue: move event to delayed queue '/block/sdb'
06:58:42 msg_exec: child [8060] created
06:58:42 running_moveto_queue: move sequence 11 [8060] to running queue '/block/sdb'
06:58:42 msg_dump: sequence 12, 'remove', '/block/sda', 'block'
06:58:42 msg_exec: child [8061] created
06:58:42 running_moveto_queue: move sequence 12 [8061] to running queue '/block/sda'
06:58:42 msg_dump: sequence 13, 'add', '/block/sda', 'block'
06:58:42 msg_exec: delay exec of sequence 13, [8061] already working on '/block/sda'
06:58:42 delayed_moveto_queue: move event to delayed queue '/block/sda'
06:58:42 msg_exec: child [8062] created
06:58:42 running_moveto_queue: move sequence 13 [8062] to running queue '/block/sda'
06:58:42 msg_dump: sequence 14, 'add', '/block/sdb', 'block'
06:58:42 msg_exec: delay exec of sequence 14, [8057] already working on '/block/sdb'
06:58:42 delayed_moveto_queue: move event to delayed queue '/block/sdb'
06:58:42 msg_exec: child [8063] created
06:58:42 running_moveto_queue: move sequence 14 [8063] to running queue '/block/sdb'
06:58:42 msg_dump: sequence 15, 'add', '/block/sdc', 'block'
06:58:42 msg_exec: delay exec of sequence 15, [8058] already working on '/block/sdc'
06:58:42 delayed_moveto_queue: move event to delayed queue '/block/sdc'
06:58:42 msg_exec: child [8064] created
06:58:42 running_moveto_queue: move sequence 15 [8064] to running queue '/block/sdc'
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8057
06:58:43 sig_handler: exec finished, pid 8058
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8059
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8060
06:58:43 sig_handler: exec finished, pid 8061
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8062
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8063
06:58:43 sig_handler: caught signal 17
06:58:43 sig_handler: exec finished, pid 8064


[-- Attachment #2: 01-udevd-execqueue.patch --]
[-- Type: text/plain, Size: 12631 bytes --]

diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Jan 27 07:29:28 2004
+++ b/Makefile	Tue Jan 27 07:29:28 2004
@@ -232,6 +232,8 @@
 	@echo \#define UDEV_CONFIG_FILE	\"$(configdir)\udev.conf\" >> $@
 	@echo \#define UDEV_RULES_FILE	\"$(configdir)\udev.rules\" >> $@
 	@echo \#define UDEV_PERMISSION_FILE	\"$(configdir)\udev.permissions\" >> $@
+	@echo \#define UDEV_BIN		\"$(PWD)/udev\" >> $@
+	@echo \#define UDEVD_BIN	\"$(PWD)/udevd\" >> $@
 
 # config files automatically generated
 GEN_CONFIGS =	$(LOCAL_CFG_DIR)/udev.conf
diff -Nru a/test/udevd_test.sh b/test/udevd_test.sh
--- a/test/udevd_test.sh	Tue Jan 27 07:29:28 2004
+++ b/test/udevd_test.sh	Tue Jan 27 07:29:28 2004
@@ -3,7 +3,12 @@
 # kill daemon, first event will start it again
 killall udevd
 
-# connect(123) - disconnect(456) - connect(789) sequence of sda/sdb/sdc
+# 3 x connect/disconnect sequence of sda/sdb/sdc
+
+export SEQNUM=3
+export ACTION=add
+export DEVPATH=/block/sdc
+./udevsend block
 
 export SEQNUM=1
 export ACTION=add
@@ -17,36 +22,64 @@
 
 export SEQNUM=4
 export ACTION=remove
-export DEVPATH=/block/sda
-./udevsend block
-
-export SEQNUM=3
-export ACTION=add
 export DEVPATH=/block/sdc
 ./udevsend block
 
-export SEQNUM=6
+export SEQNUM=5
 export ACTION=remove
-export DEVPATH=/block/sdc
+export DEVPATH=/block/sdb
 ./udevsend block
 
-export SEQNUM=5
-export ACTION=remove
+export SEQNUM=8
+export ACTION=add
 export DEVPATH=/block/sdb
 ./udevsend block
 
+export SEQNUM=6
+export ACTION=remove
+export DEVPATH=/block/sda
+./udevsend block
+
 export SEQNUM=7
 export ACTION=add
 export DEVPATH=/block/sda
 #./udevsend block
 
+sleep 2
+
 export SEQNUM=9
 export ACTION=add
 export DEVPATH=/block/sdc
 ./udevsend block
 
-export SEQNUM=8
+export SEQNUM=11
+export ACTION=remove
+export DEVPATH=/block/sdb
+./udevsend block
+
+export SEQNUM=10
+export ACTION=remove
+export DEVPATH=/block/sdc
+./udevsend block
+
+export SEQNUM=13
+export ACTION=add
+export DEVPATH=/block/sda
+./udevsend block
+
+export SEQNUM=14
 export ACTION=add
 export DEVPATH=/block/sdb
 ./udevsend block
 
+export SEQNUM=15
+export ACTION=add
+export DEVPATH=/block/sdc
+./udevsend block
+
+sleep 2
+
+export SEQNUM=12
+export ACTION=remove
+export DEVPATH=/block/sda
+./udevsend block
diff -Nru a/udev.c b/udev.c
--- a/udev.c	Tue Jan 27 07:29:28 2004
+++ b/udev.c	Tue Jan 27 07:29:28 2004
@@ -45,7 +45,6 @@
 	switch (signum) {
 		case SIGINT:
 		case SIGTERM:
-		case SIGKILL:
 			sysbus_disconnect();
 			udevdb_exit();
 			exit(20 + signum);
@@ -143,7 +142,6 @@
 	/* set up a default signal handler for now */
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
-	signal(SIGKILL, sig_handler);
 
 	/* initialize the naming deamon */
 	namedev_init();
diff -Nru a/udevd.c b/udevd.c
--- a/udevd.c	Tue Jan 27 07:29:28 2004
+++ b/udevd.c	Tue Jan 27 07:29:28 2004
@@ -38,27 +38,42 @@
 
 #include "list.h"
 #include "udev.h"
+#include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
+
 #define BUFFER_SIZE			1024
 
+static int running_remove_queue(pid_t pid);
+static int msg_exec(struct hotplug_msg *msg);
+
 static int expect_seqnum = 0;
 static int lock_file = -1;
 static char *lock_filename = ".udevd_lock";
 
 LIST_HEAD(msg_list);
+LIST_HEAD(running_list);
+LIST_HEAD(delayed_list);
 
 static void sig_handler(int signum)
 {
+	pid_t pid;
+
 	dbg("caught signal %d", signum);
 	switch (signum) {
 	case SIGALRM:
 		dbg("event timeout reached");
 		break;
+	case SIGCHLD:
+		/* catch signals from exiting childs */
+		while ( (pid = waitpid(-1, NULL, WNOHANG)) > 0) {
+			dbg("exec finished, pid %d", pid);
+			running_remove_queue(pid);
+		}
+		break;
 	case SIGINT:
 	case SIGTERM:
-	case SIGKILL:
 		if (lock_file >= 0) {
 			close(lock_file);
 			unlink(lock_filename);
@@ -70,34 +85,104 @@
 	}
 }
 
-static void dump_queue(void)
+static void set_timeout(int seconds)
 {
-	struct hotplug_msg *msg;
+	alarm(seconds);
+	dbg("set timeout in %d seconds", seconds);
+}
 
-	list_for_each_entry(msg, &msg_list, list)
-		dbg("sequence %d in queue", msg->seqnum);
+static int running_moveto_queue(struct hotplug_msg *msg)
+{
+	dbg("move sequence %d [%d] to running queue '%s'",
+	    msg->seqnum, msg->pid, msg->devpath);
+	list_move_tail(&msg->list, &running_list);
+	return 0;
+}
+
+static int running_remove_queue(pid_t  pid)
+{
+	struct hotplug_msg *child;
+	struct hotplug_msg *tmp_child;
+
+	list_for_each_entry_safe(child, tmp_child, &running_list, list)
+		if (child->pid == pid) {
+			list_del_init(&child->list);
+			free(child);
+			return 0;
+		}
+	return -EINVAL;
+}
+
+static pid_t running_getpid_by_devpath(struct hotplug_msg *msg)
+{
+	struct hotplug_msg *child;
+	struct hotplug_msg *tmp_child;
+
+	list_for_each_entry_safe(child, tmp_child, &running_list, list)
+		if (strncmp(child->devpath, msg->devpath, sizeof(child->devpath)) == 0)
+			return child->pid;
+	return 0;
 }
 
-static void dump_msg(struct hotplug_msg *msg)
+static void delayed_dump_queue(void)
+{
+	struct hotplug_msg *child;
+
+	list_for_each_entry(child, &delayed_list, list)
+		dbg("event for '%s' in queue", child->devpath);
+}
+
+static int delayed_moveto_queue(struct hotplug_msg *msg)
+{
+	dbg("move event to delayed queue '%s'", msg->devpath);
+	list_move_tail(&msg->list, &delayed_list);
+	return 0;
+}
+
+static void delayed_check_queue(void)
+{
+	struct hotplug_msg *delayed_child;
+	struct hotplug_msg *running_child;
+	struct hotplug_msg *tmp_child;
+
+	/* see if we have delayed exec's that can run now */
+	list_for_each_entry_safe(delayed_child, tmp_child, &delayed_list, list)
+		list_for_each_entry_safe(running_child, tmp_child, &running_list, list)
+			if (strncmp(delayed_child->devpath, running_child->devpath,
+			    sizeof(running_child->devpath)) == 0) {
+				dbg("delayed exec for '%s' can run now", delayed_child->devpath);
+				msg_exec(delayed_child);
+			}
+}
+
+static void msg_dump(struct hotplug_msg *msg)
 {
 	dbg("sequence %d, '%s', '%s', '%s'",
 	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static int dispatch_msg(struct hotplug_msg *msg)
+static int msg_exec(struct hotplug_msg *msg)
 {
 	pid_t pid;
 
-	dump_msg(msg);
+	msg_dump(msg);
 
 	setenv("ACTION", msg->action, 1);
 	setenv("DEVPATH", msg->devpath, 1);
 
+	/* delay exec, if we already have a udev working on the same devpath */
+	pid = running_getpid_by_devpath(msg);
+	if (pid != 0) {
+		dbg("delay exec of sequence %d, [%d] already working on '%s'",
+		    msg->seqnum, pid, msg->devpath);
+		delayed_moveto_queue(msg);
+	}
+
 	pid = fork();
 	switch (pid) {
 	case 0:
 		/* child */
-		execl(UDEV_EXEC, "udev", msg->subsystem, NULL);
+		execl(UDEV_BIN, "udev", msg->subsystem, NULL);
 		dbg("exec of child failed");
 		exit(1);
 		break;
@@ -105,18 +190,23 @@
 		dbg("fork of child failed");
 		return -1;
 	default:
-		wait(NULL);
+		/* exec in background, get the SIGCHLD with the sig handler */
+		msg->pid = pid;
+		running_moveto_queue(msg);
+		break;
 	}
 	return 0;
 }
 
-static void set_timeout(int seconds)
+static void msg_dump_queue(void)
 {
-	alarm(seconds);
-	dbg("set timeout in %d seconds", seconds);
+	struct hotplug_msg *msg;
+
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static void check_queue(void)
+static void msg_check_queue(void)
 {
 	struct hotplug_msg *msg;
 	struct hotplug_msg *tmp_msg;
@@ -127,30 +217,32 @@
 	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
 		if (msg->seqnum != expect_seqnum)
 			break;
-		dispatch_msg(msg);
+		msg_exec(msg);
 		expect_seqnum++;
-		list_del_init(&msg->list);
-		free(msg);
 	}
 
-	/* recalculate timeout */
+	/* recalculate next timeout */
 	if (list_empty(&msg_list) == 0) {
 		msg_age = time(NULL) - msg->queue_time;
-		if (msg_age > EVENT_TIMEOUT_SECONDS-1) {
+		if (msg_age > EVENT_TIMEOUT_SEC-1) {
 			info("event %d, age %li seconds, skip event %d-%d",
 			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
 			expect_seqnum = msg->seqnum;
 			goto recheck;
 		}
-		set_timeout(EVENT_TIMEOUT_SECONDS - msg_age);
+
+		/* the first sequence gets its own timeout */
+		if (expect_seqnum == 0) {
+			msg_age = EVENT_TIMEOUT_SEC - FIRST_EVENT_TIMEOUT_SEC;
+			expect_seqnum = 1;
+		}
+
+		set_timeout(EVENT_TIMEOUT_SEC - msg_age);
 		return;
 	}
-
-	/* queue is empty */
-	set_timeout(UDEVD_TIMEOUT_SECONDS);
 }
 
-static int queue_msg(struct hotplug_msg *msg)
+static int msg_add_queue(struct hotplug_msg *msg)
 {
 	struct hotplug_msg *new_msg;
 	struct hotplug_msg *tmp_msg;
@@ -182,7 +274,7 @@
 	char buf[BUFFER_SIZE];
 	int ret;
 
-	key = ftok(UDEVD_EXEC, IPC_KEY_ID);
+	key = ftok(UDEVD_BIN, IPC_KEY_ID);
 	msg = (struct hotplug_msg *) buf;
 	msgid = msgget(key, IPC_CREAT);
 	if (msgid == -1) {
@@ -192,41 +284,20 @@
 	while (1) {
 		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
 		if (ret != -1) {
-			/* init the expected sequence with value from first call */
-			if (expect_seqnum == 0) {
-				expect_seqnum = msg->seqnum;
-				dbg("init next expected sequence number to %d", expect_seqnum);
-			}
-			dbg("current sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
-			if (msg->seqnum == expect_seqnum) {
-				/* execute expected event */
-				dispatch_msg(msg);
-				expect_seqnum++;
-				check_queue();
-				dump_queue();
+			dbg("received sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
+			if (msg->seqnum >= expect_seqnum) {
+				msg_add_queue(msg);
+				msg_dump_queue();
+				msg_check_queue();
 				continue;
 			}
-			if (msg->seqnum > expect_seqnum) {
-				/* something missing, queue event*/
-				queue_msg(msg);
-				check_queue();
-				dump_queue();
-				continue;
-			}
-			dbg("too late for event with sequence %d, even skipped ", msg->seqnum);
+			dbg("too late for event with sequence %d, event skipped ", msg->seqnum);
 		} else {
 			if (errno == EINTR) {
-				/* timeout */
-				if (list_empty(&msg_list)) {
-					info("we have nothing to do, so daemon exits...");
-					if (lock_file >= 0) {
-						close(lock_file);
-						unlink(lock_filename);
-					}
-					exit(0);
-				}
-				check_queue();
-				dump_queue();
+				msg_check_queue();
+				msg_dump_queue();
+				delayed_check_queue();
+				delayed_dump_queue();
 				continue;
 			}
 			dbg("ipc message receive error '%s'", strerror(errno));
@@ -266,11 +337,8 @@
 	/* set up signal handler */
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
-	signal(SIGKILL, sig_handler);
 	signal(SIGALRM, sig_handler);
-
-	/* we exit if we have nothing to do, next event will start us again */
-	set_timeout(UDEVD_TIMEOUT_SECONDS);
+	signal(SIGCHLD, sig_handler);
 
 	work();
 	exit(0);
diff -Nru a/udevd.h b/udevd.h
--- a/udevd.h	Tue Jan 27 07:29:28 2004
+++ b/udevd.h	Tue Jan 27 07:29:28 2004
@@ -23,18 +23,18 @@
 
 #include "list.h"
 
-#define UDEV_EXEC			"./udev"
-#define UDEVD_EXEC			"./udevd"
-#define UDEVD_TIMEOUT_SECONDS		60
-#define EVENT_TIMEOUT_SECONDS		5
+#define FIRST_EVENT_TIMEOUT_SEC		1
+#define EVENT_TIMEOUT_SEC		5
+#define UDEVSEND_RETRY_COUNT		50 /* x 10 millisec */
 
-#define IPC_KEY_ID			0
+#define IPC_KEY_ID			1
 #define HOTPLUGMSGTYPE			44
 
 
 struct hotplug_msg {
 	long mtype;
 	struct list_head list;
+	pid_t pid;
 	int seqnum;
 	time_t queue_time;
 	char action[8];
diff -Nru a/udevsend.c b/udevsend.c
--- a/udevsend.c	Tue Jan 27 07:29:28 2004
+++ b/udevsend.c	Tue Jan 27 07:29:28 2004
@@ -34,6 +34,7 @@
 #include <wait.h>
 
 #include "udev.h"
+#include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
@@ -64,7 +65,7 @@
 static int build_hotplugmsg(struct hotplug_msg *msg, char *action,
 			    char *devpath, char *subsystem, int seqnum)
 {
-	memset(msg, 0x00, sizeof(msg));
+	memset(msg, 0x00, sizeof(*msg));
 	msg->mtype = HOTPLUGMSGTYPE;
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
@@ -88,7 +89,7 @@
 			/* daemon */
 			setsid();
 			chdir("/");
-			execl(UDEVD_EXEC, "udevd", NULL);
+			execl(UDEVD_BIN, "udevd", NULL);
 			dbg("exec of daemon failed");
 			exit(1);
 		case -1:
@@ -150,7 +151,8 @@
 	seq = atoi(seqnum);
 
 	/* create ipc message queue or get id of our existing one */
-	key = ftok(UDEVD_EXEC, IPC_KEY_ID);
+	key = ftok(UDEVD_BIN, IPC_KEY_ID);
+	dbg("using ipc queue 0x%0x", key);
 	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
 	msgid = msgget(key, IPC_CREAT);
 	if (msgid == -1) {
@@ -168,7 +170,7 @@
 	/* get state of ipc queue */
 	tspec.tv_sec = 0;
 	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = 30;
+	loop = UDEVSEND_RETRY_COUNT;
 	while (loop--) {
 		retval = msgctl(msgid, IPC_STAT, &msg_queue);
 		if (retval == -1) {

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (6 preceding siblings ...)
  2004-01-27  6:56 ` Kay Sievers
@ 2004-01-27 18:55 ` Greg KH
  2004-01-27 19:08 ` Kay Sievers
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-01-27 18:55 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Jan 26, 2004 at 11:56:20PM +0100, Kay Sievers wrote:
> 
> All problems magically go away with threads, cause we share the same
> address space and let the kernel schedule our tasks.

Ok, that makes more sense.  Thanks for explaining it.

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (7 preceding siblings ...)
  2004-01-27 18:55 ` Greg KH
@ 2004-01-27 19:08 ` Kay Sievers
  2004-01-27 19:13 ` Greg KH
                   ` (21 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-27 19:08 UTC (permalink / raw)
  To: linux-hotplug

On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > >   1. We are much too slow.
> > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > >      is much much faster than a 'add', so we have a problem.
> > > > >      Question: is it neccessary to order events for different devpath's?
> > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > >      working on the same devpath.
> > > > 
> > > > But how will we keep track of that?  It's probably easier just to wait
> > > > for each one to finish, right?
> > > 
> > > We leave the message in the queue until we reach the SIGCHLD for this
> > > pid. So we can search the queue if we are already working on this devpath,
> > > and delay the new exec until the former exec comes back.
> > 
> > Ok, if that isn't too much trouble.
> > 
> > > Is it feasible to run in parallel for different paths, or can you think
> > > of any problem?
> > 
> > I can't think of any problem with that.
> 
> Here is the next round. We have three queues now. All incoming messages
> are queued in msg_list and if nothing is missing we move it to the
> running_list and exec in the background.
> If the exec comes back, it removes the message from the running_list and
> frees the message.
> 
> Before we exec, we check the running_list if there is a udev running on
> the same device path. If yes, we move the message to the delay_list. If
> the former exec comes back, we move the message to the running_list and
> exec it.

Oh, sorry forget about it now.
I will come up with something better tested.

Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (8 preceding siblings ...)
  2004-01-27 19:08 ` Kay Sievers
@ 2004-01-27 19:13 ` Greg KH
  2004-01-28 21:47 ` Kay Sievers
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-01-27 19:13 UTC (permalink / raw)
  To: linux-hotplug

On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > >   1. We are much too slow.
> > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > >      working on the same devpath.
> > > > > 
> > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > for each one to finish, right?
> > > > 
> > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > pid. So we can search the queue if we are already working on this devpath,
> > > > and delay the new exec until the former exec comes back.
> > > 
> > > Ok, if that isn't too much trouble.
> > > 
> > > > Is it feasible to run in parallel for different paths, or can you think
> > > > of any problem?
> > > 
> > > I can't think of any problem with that.
> > 
> > Here is the next round. We have three queues now. All incoming messages
> > are queued in msg_list and if nothing is missing we move it to the
> > running_list and exec in the background.
> > If the exec comes back, it removes the message from the running_list and
> > frees the message.
> > 
> > Before we exec, we check the running_list if there is a udev running on
> > the same device path. If yes, we move the message to the delay_list. If
> > the former exec comes back, we move the message to the running_list and
> > exec it.
> 
> Oh, sorry forget about it now.
> I will come up with something better tested.

Oops, I just applied this version :)

I'll try testing this later on today.

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (9 preceding siblings ...)
  2004-01-27 19:13 ` Greg KH
@ 2004-01-28 21:47 ` Kay Sievers
  2004-01-29  1:52 ` Kay Sievers
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-28 21:47 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 15285 bytes --]

On Tue, Jan 27, 2004 at 11:13:09AM -0800, Greg KH wrote:
> On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> > On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > > >   1. We are much too slow.
> > > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > > >      working on the same devpath.
> > > > > > 
> > > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > > for each one to finish, right?
> > > > > 
> > > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > > pid. So we can search the queue if we are already working on this devpath,
> > > > > and delay the new exec until the former exec comes back.
> > > > 
> > > > Ok, if that isn't too much trouble.
> > > > 
> > > > > Is it feasible to run in parallel for different paths, or can you think
> > > > > of any problem?
> > > > 
> > > > I can't think of any problem with that.
> > > 
> > > Here is the next round. We have three queues now. All incoming messages
> > > are queued in msg_list and if nothing is missing we move it to the
> > > running_list and exec in the background.
> > > If the exec comes back, it removes the message from the running_list and
> > > frees the message.
> > > 
> > > Before we exec, we check the running_list if there is a udev running on
> > > the same device path. If yes, we move the message to the delay_list. If
> > > the former exec comes back, we move the message to the running_list and
> > > exec it.
> > 
> > Oh, sorry forget about it now.
> > I will come up with something better tested.
> 
> Oops, I just applied this version :)
> 
> I'll try testing this later on today.

Oh, couldn't resist to try threads.
It's a multithreaded udevd that communicates through a localhost socket.
The message includes a magic with the udev version, so we don't accept
older udevsend's.

No need for locking, cause we can't bind two sockets on the same address.
The daemon tries to connect and if it fails it starts the daemon.

We create a thread for every incoming connection, handle over the socket,
sort the messages in the global message queue and exit the thread.
Huh, that was easy with threads :)

With the addition of a message we wakeup the queue manager thread and
handle timeouts or move the message to the global exec list. This wakes
up the exec list manager who looks if a process is already running for this
device path.
If yes, the exec is delayed otherwise we create a thread that execs udev.
n the background. With the return of udev we free the message and wakeup
the exec list manager to look if something is pending.

It is just a quick shot, cause I couldn't solve the problems with fork an
scheduling and I wanted to see if I'm to stupid  :)
But if anybody with a better idea or more experience with I/O scheduling
we may go another way. The remaining problem is that klibc doesn't support
threads.

By now, we don't exec anything, it's just a sleep 3 for every exec,
but you can see the queue management by watching syslog and do:

  DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc

thanks,
Kay


The result of the test script follows. I've sent SEQNUM=0 before starting the
script, so we don't wait for the initial timeout. Look at exec 9 -> 12 -> 10
for the DEVPATH logic:

Jan 28 22:23:41 pim udev[24687]: main: connect failed, try starting daemon...
Jan 28 22:23:41 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 0
Jan 28 22:23:41 pim udev[24689]: exec_queue_manager: exec list manager
Jan 28 22:23:41 pim udev[24687]: main: daemon started
Jan 28 22:23:41 pim udev[24689]: msg_queue_insert: add message seq 0
Jan 28 22:23:41 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 0
Jan 28 22:23:41 pim udev[24689]: msg_queue_manager: moved seq 0 to exec, next expected is 1
Jan 28 22:23:41 pim udev[24689]: exec_queue_manager: exec list manager
Jan 28 22:23:41 pim udev[24689]: run_threads: ==> exec seq 0 working at '/'
Jan 28 22:23:41 pim udev[24689]: exec_queue_manager: moved seq 0 to running list
Jan 28 22:23:44 pim udev[24689]: run_threads: <== exec seq 0 came back
Jan 28 22:23:44 pim udev[24689]: exec_queue_manager: exec list manager
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 3
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 1
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 1
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 2
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 4
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 5
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 8
Jan 28 22:23:51 pim udev[24689]: msg_queue_insert: add message seq 6
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 1 to exec, next expected is 2
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 2 to exec, next expected is 3
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 3 to exec, next expected is 4
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 4 to exec, next expected is 5
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 5 to exec, next expected is 6
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: moved seq 6 to exec, next expected is 7
Jan 28 22:23:51 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:51 pim udev[24689]: msg_queue_manager: next event expires in 10 seconds
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: exec list manager

Jan 28 22:23:51 pim udev[24689]: run_threads: ==> exec seq 1 working at '/block/sda'
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: moved seq 1 to running list

Jan 28 22:23:51 pim udev[24689]: run_threads: ==> exec seq 2 working at '/block/sdb'
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: moved seq 2 to running list

Jan 28 22:23:51 pim udev[24689]: run_threads: ==> exec seq 3 working at '/block/sdc'
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: moved seq 3 to running list
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: delay seq 4, cause seq 3 already working on '/block/sdc'
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: delay seq 5, cause seq 2 already working on '/block/sdb'
Jan 28 22:23:51 pim udev[24689]: exec_queue_manager: delay seq 6, cause seq 1 already working on '/block/sda'
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 9
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 11
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 10
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 9 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 10 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 11 in queue
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: next event expires in 8 seconds
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 13
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 9 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 10 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 11 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 13 in queue
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: next event expires in 8 seconds
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 14
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 9 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 10 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 11 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 13 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 14 in queue
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: next event expires in 8 seconds
Jan 28 22:23:53 pim udev[24689]: msg_queue_insert: add message seq 15
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 9 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 10 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 11 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 13 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 14 in queue
Jan 28 22:23:53 pim udev[24689]: msg_dump_queue: sequence 15 in queue
Jan 28 22:23:53 pim udev[24689]: msg_queue_manager: next event expires in 8 seconds
Jan 28 22:23:54 pim udev[24689]: run_threads: <== exec seq 1 came back
Jan 28 22:23:54 pim udev[24689]: run_threads: <== exec seq 2 came back
Jan 28 22:23:54 pim udev[24689]: run_threads: <== exec seq 3 came back
Jan 28 22:23:54 pim udev[24689]: exec_queue_manager: exec list manager

Jan 28 22:23:54 pim udev[24689]: run_threads: ==> exec seq 4 working at '/block/sdc'
Jan 28 22:23:54 pim udev[24689]: exec_queue_manager: moved seq 4 to running list

Jan 28 22:23:54 pim udev[24689]: run_threads: ==> exec seq 5 working at '/block/sdb'
Jan 28 22:23:54 pim udev[24689]: exec_queue_manager: moved seq 5 to running list

Jan 28 22:23:54 pim udev[24689]: run_threads: ==> exec seq 6 working at '/block/sda'
Jan 28 22:23:54 pim udev[24689]: exec_queue_manager: moved seq 6 to running list
Jan 28 22:23:55 pim udev[24689]: msg_queue_insert: add message seq 12
Jan 28 22:23:55 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 8 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 9 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 10 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 11 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 12 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 13 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 14 in queue
Jan 28 22:23:55 pim udev[24689]: msg_dump_queue: sequence 15 in queue
Jan 28 22:23:55 pim udev[24689]: msg_queue_manager: next event expires in 6 seconds
Jan 28 22:23:57 pim udev[24689]: run_threads: <== exec seq 4 came back
Jan 28 22:23:57 pim udev[24689]: run_threads: <== exec seq 5 came back
Jan 28 22:23:57 pim udev[24689]: run_threads: <== exec seq 6 came back
Jan 28 22:23:57 pim udev[24689]: exec_queue_manager: exec list manager
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: msg queue manager, next expected is 7
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 8 to exec, reset next expected to 9
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 9 to exec, next expected is 10
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 10 to exec, next expected is 11
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 11 to exec, next expected is 12
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 12 to exec, next expected is 13
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 13 to exec, next expected is 14
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 14 to exec, next expected is 15
Jan 28 22:24:01 pim udev[24689]: msg_queue_manager: moved seq 15 to exec, next expected is 16
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: exec list manager

Jan 28 22:24:01 pim udev[24689]: run_threads: ==> exec seq 8 working at '/block/sdb'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: moved seq 8 to running list

Jan 28 22:24:01 pim udev[24689]: run_threads: ==> exec seq 9 working at '/block/sdc'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: moved seq 9 to running list
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: delay seq 10, cause seq 9 already working on '/block/sdc'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: delay seq 11, cause seq 8 already working on '/block/sdb'

Jan 28 22:24:01 pim udev[24689]: run_threads: ==> exec seq 12 working at '/block/sda'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: moved seq 12 to running list
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: delay seq 13, cause seq 12 already working on '/block/sda'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: delay seq 14, cause seq 8 already working on '/block/sdb'
Jan 28 22:24:01 pim udev[24689]: exec_queue_manager: delay seq 15, cause seq 9 already working on '/block/sdc'
Jan 28 22:24:04 pim udev[24689]: run_threads: <== exec seq 8 came back
Jan 28 22:24:04 pim udev[24689]: run_threads: <== exec seq 9 came back
Jan 28 22:24:04 pim udev[24689]: run_threads: <== exec seq 12 came back
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: exec list manager

Jan 28 22:24:04 pim udev[24689]: run_threads: ==> exec seq 10 working at '/block/sdc'
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: moved seq 10 to running list

Jan 28 22:24:04 pim udev[24689]: run_threads: ==> exec seq 11 working at '/block/sdb'
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: moved seq 11 to running list

Jan 28 22:24:04 pim udev[24689]: run_threads: ==> exec seq 13 working at '/block/sda'
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: moved seq 13 to running list
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: delay seq 14, cause seq 11 already working on '/block/sdb'
Jan 28 22:24:04 pim udev[24689]: exec_queue_manager: delay seq 15, cause seq 10 already working on '/block/sdc'
Jan 28 22:24:07 pim udev[24689]: run_threads: <== exec seq 10 came back
Jan 28 22:24:07 pim udev[24689]: run_threads: <== exec seq 11 came back
Jan 28 22:24:07 pim udev[24689]: run_threads: <== exec seq 13 came back
Jan 28 22:24:07 pim udev[24689]: exec_queue_manager: exec list manager

Jan 28 22:24:07 pim udev[24689]: run_threads: ==> exec seq 14 working at '/block/sdb'
Jan 28 22:24:07 pim udev[24689]: exec_queue_manager: moved seq 14 to running list

Jan 28 22:24:07 pim udev[24689]: run_threads: ==> exec seq 15 working at '/block/sdc'
Jan 28 22:24:07 pim udev[24689]: exec_queue_manager: moved seq 15 to running list
Jan 28 22:24:10 pim udev[24689]: run_threads: <== exec seq 14 came back
Jan 28 22:24:10 pim udev[24689]: run_threads: <== exec seq 15 came back
Jan 28 22:24:10 pim udev[24689]: exec_queue_manager: exec list manager


[-- Attachment #2: 01-udevd-threads.patch --]
[-- Type: text/plain, Size: 20725 bytes --]

===== Makefile 1.93 vs edited =====
--- 1.93/Makefile	Tue Jan 27 08:29:28 2004
+++ edited/Makefile	Wed Jan 28 22:21:26 2004
@@ -255,7 +255,7 @@
 	$(STRIPCMD) $@
 
 $(DAEMON): udevd.h udevd.o udevd.o logging.o
-	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
+	$(LD) $(LDFLAGS) -lpthread -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $@
 
 $(SENDER): udevd.h udevsend.o udevd.o logging.o
===== udevd.c 1.7 vs edited =====
--- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
+++ edited/udevd.c	Wed Jan 28 22:22:04 2004
@@ -3,7 +3,6 @@
  *
  * Userspace devfs
  *
- * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
@@ -24,7 +23,6 @@
 
 #include <stddef.h>
 #include <sys/types.h>
-#include <sys/ipc.h>
 #include <sys/wait.h>
 #include <sys/msg.h>
 #include <signal.h>
@@ -35,6 +33,11 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <pthread.h>
 
 #include "list.h"
 #include "udev.h"
@@ -43,302 +46,311 @@
 #include "logging.h"
 
 
-#define BUFFER_SIZE			1024
+static pthread_mutex_t  msg_lock;
+static pthread_mutex_t  msg_active_lock;
+static pthread_cond_t msg_active;
+
+static pthread_mutex_t  exec_lock;
+static pthread_mutex_t  exec_active_lock;
+static pthread_cond_t exec_active;
 
-static int running_remove_queue(pid_t pid);
-static int msg_exec(struct hotplug_msg *msg);
+static pthread_mutex_t  running_lock;
 
-static int expect_seqnum = 0;
-static int lock_file = -1;
-static char *lock_filename = ".udevd_lock";
+static int expected_seqnum = 0;
 
 LIST_HEAD(msg_list);
+LIST_HEAD(exec_list);
 LIST_HEAD(running_list);
-LIST_HEAD(delayed_list);
 
-static void sig_handler(int signum)
+
+static void msg_dump_queue(void)
 {
-	pid_t pid;
+	struct hotplug_msg *msg;
 
-	dbg("caught signal %d", signum);
-	switch (signum) {
-	case SIGALRM:
-		dbg("event timeout reached");
-		break;
-	case SIGCHLD:
-		/* catch signals from exiting childs */
-		while ( (pid = waitpid(-1, NULL, WNOHANG)) > 0) {
-			dbg("exec finished, pid %d", pid);
-			running_remove_queue(pid);
-		}
-		break;
-	case SIGINT:
-	case SIGTERM:
-		if (lock_file >= 0) {
-			close(lock_file);
-			unlink(lock_filename);
-		}
-		exit(20 + signum);
-		break;
-	default:
-		dbg("unhandled signal");
-	}
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static void set_timeout(int seconds)
+static void msg_dump(struct hotplug_msg *msg)
 {
-	alarm(seconds);
-	dbg("set timeout in %d seconds", seconds);
+	dbg("sequence %d, '%s', '%s', '%s'",
+	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static int running_moveto_queue(struct hotplug_msg *msg)
+/* allocates a new message */
+static struct hotplug_msg *msg_create(void)
 {
-	dbg("move sequence %d [%d] to running queue '%s'",
-	    msg->seqnum, msg->pid, msg->devpath);
-	list_move_tail(&msg->list, &running_list);
-	return 0;
+	struct hotplug_msg *new_msg;
+
+	new_msg = malloc(sizeof(struct hotplug_msg));
+	if (new_msg == NULL) {
+		dbg("error malloc");
+		return NULL;
+	}
+	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
+	return new_msg;
 }
 
-static int running_remove_queue(pid_t  pid)
+/* orders the message in the queue by sequence number */
+static void msg_queue_insert(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
+	struct hotplug_msg *loop_msg;
 
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (child->pid == pid) {
-			list_del_init(&child->list);
-			free(child);
-			return 0;
-		}
-	return -EINVAL;
-}
+	dbg("add message seq %d", msg->seqnum);
 
-static pid_t running_getpid_by_devpath(struct hotplug_msg *msg)
-{
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
+	/* sort message by sequence number into list*/
+	list_for_each_entry(loop_msg, &msg_list, list)
+		if (loop_msg->seqnum > msg->seqnum)
+			break;
+	list_add_tail(&msg->list, &loop_msg->list);
 
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (strncmp(child->devpath, msg->devpath, sizeof(child->devpath)) == 0)
-			return child->pid;
-	return 0;
-}
+	/* store timestamp of queuing */
+	msg->queue_time = time(NULL);
 
-static void delayed_dump_queue(void)
-{
-	struct hotplug_msg *child;
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&msg_active_lock);
+	pthread_cond_signal(&msg_active);
+	pthread_mutex_unlock(&msg_active_lock);
 
-	list_for_each_entry(child, &delayed_list, list)
-		dbg("event for '%s' in queue", child->devpath);
+	return ;
 }
 
-static int delayed_moveto_queue(struct hotplug_msg *msg)
+/* forks event and removes event from run queue when finished */
+static void *run_threads(void * parm)
 {
-	dbg("move event to delayed queue '%s'", msg->devpath);
-	list_move_tail(&msg->list, &delayed_list);
-	return 0;
-}
+	struct hotplug_msg *run_msg;
 
-static void delayed_check_queue(void)
-{
-	struct hotplug_msg *delayed_child;
-	struct hotplug_msg *running_child;
-	struct hotplug_msg *tmp_child;
-
-	/* see if we have delayed exec's that can run now */
-	list_for_each_entry_safe(delayed_child, tmp_child, &delayed_list, list)
-		list_for_each_entry_safe(running_child, tmp_child, &running_list, list)
-			if (strncmp(delayed_child->devpath, running_child->devpath,
-			    sizeof(running_child->devpath)) == 0) {
-				dbg("delayed exec for '%s' can run now", delayed_child->devpath);
-				msg_exec(delayed_child);
-			}
+	run_msg = parm;
+
+	dbg("==> exec seq %d working at '%s'", run_msg->seqnum, run_msg->devpath);
+	sleep(3);
+	dbg("<== exec seq %d came back", run_msg->seqnum);
+
+	/* remove event from run list */
+	pthread_mutex_lock(&running_lock);
+	list_del_init(&run_msg->list);
+	pthread_mutex_unlock(&running_lock);
+
+	free(run_msg);
+
+	/* signal queue activity to exec manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+
+	pthread_exit(0);
 }
 
-static void msg_dump(struct hotplug_msg *msg)
+/* returns already running task with devpath */
+static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
 {
-	dbg("sequence %d, '%s', '%s', '%s'",
-	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
+
+	list_for_each_entry_safe(loop_msg, tmp_msg, &running_list, list)
+		if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
+			return loop_msg;
+	return NULL;
 }
 
-static int msg_exec(struct hotplug_msg *msg)
+/* queue management executes the events and delays events for the same devpath */
+static void *exec_queue_manager(void * parm)
 {
-	pid_t pid;
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
+	struct hotplug_msg *msg;
+	pthread_t run_tid;
 
-	msg_dump(msg);
+	while (1) {
+		dbg("exec list manager");
+		pthread_mutex_lock(&exec_lock);
 
-	setenv("ACTION", msg->action, 1);
-	setenv("DEVPATH", msg->devpath, 1);
+		list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, list) {
+			msg = running_with_devpath(loop_msg);
+			if (msg == NULL) {
+				/* move event to run list */
+				pthread_mutex_lock(&running_lock);
+				list_move_tail(&loop_msg->list, &running_list);
+				pthread_mutex_unlock(&running_lock);
+
+				pthread_create(&run_tid, NULL, run_threads, (void *) loop_msg);
+
+				dbg("moved seq %d to running list", loop_msg->seqnum);
+			} else {
+				dbg("delay seq %d, cause seq %d already working on '%s'",
+				    loop_msg->seqnum, msg->seqnum, msg->devpath);
+			}
+		}
 
-	/* delay exec, if we already have a udev working on the same devpath */
-	pid = running_getpid_by_devpath(msg);
-	if (pid != 0) {
-		dbg("delay exec of sequence %d, [%d] already working on '%s'",
-		    msg->seqnum, pid, msg->devpath);
-		delayed_moveto_queue(msg);
-	}
+		pthread_mutex_unlock(&exec_lock);
 
-	pid = fork();
-	switch (pid) {
-	case 0:
-		/* child */
-		execl(UDEV_BIN, "udev", msg->subsystem, NULL);
-		dbg("exec of child failed");
-		exit(1);
-		break;
-	case -1:
-		dbg("fork of child failed");
-		return -1;
-	default:
-		/* exec in background, get the SIGCHLD with the sig handler */
-		msg->pid = pid;
-		running_moveto_queue(msg);
-		break;
+		/* wait for activation, new events or childs coming back */
+		pthread_mutex_lock(&exec_active_lock);
+		pthread_cond_wait(&exec_active, &exec_active_lock);
+		pthread_mutex_unlock(&exec_active_lock);
 	}
-	return 0;
 }
 
-static void msg_dump_queue(void)
+/* move message from incoming to exec queue */
+static void msg_move_exec(struct list_head *head)
 {
-	struct hotplug_msg *msg;
-
-	list_for_each_entry(msg, &msg_list, list)
-		dbg("sequence %d in queue", msg->seqnum);
+	list_move_tail(head, &exec_list);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
 }
 
-static void msg_check_queue(void)
+/* queue management thread handles the timeouts and dispatches the events */
+static void *msg_queue_manager(void * parm)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
 	struct hotplug_msg *tmp_msg;
-	time_t msg_age;
+	time_t msg_age = 0;
+	struct timespec tv;
+
+	while (1) {
+		dbg("msg queue manager, next expected is %d", expected_seqnum);
+		pthread_mutex_lock(&msg_lock);
+		pthread_mutex_lock(&exec_lock);
 
 recheck:
-	/* dispatch events until one is missing */
-	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
-		if (msg->seqnum != expect_seqnum)
-			break;
-		msg_exec(msg);
-		expect_seqnum++;
-	}
+		list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, list) {
+			/* move event with expected sequence to the exec list */
+			if (loop_msg->seqnum == expected_seqnum) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum++;
+				dbg("moved seq %d to exec, next expected is %d",
+				    loop_msg->seqnum, expected_seqnum);
+				continue;
+			}
 
-	/* recalculate next timeout */
-	if (list_empty(&msg_list) == 0) {
-		msg_age = time(NULL) - msg->queue_time;
-		if (msg_age > EVENT_TIMEOUT_SEC-1) {
-			info("event %d, age %li seconds, skip event %d-%d",
-			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
-			expect_seqnum = msg->seqnum;
-			goto recheck;
+			/* move event with expired timeout to the exec list */
+			msg_age = time(NULL) - loop_msg->queue_time;
+			if (msg_age > EVENT_TIMEOUT_SEC-1) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum = loop_msg->seqnum+1;
+				dbg("moved seq %d to exec, reset next expected to %d",
+				    loop_msg->seqnum, expected_seqnum);
+				goto recheck;
+			} else {
+				break;
+			}
 		}
 
-		/* the first sequence gets its own timeout */
-		if (expect_seqnum == 0) {
-			msg_age = EVENT_TIMEOUT_SEC - FIRST_EVENT_TIMEOUT_SEC;
-			expect_seqnum = 1;
+		msg_dump_queue();
+		pthread_mutex_unlock(&exec_lock);
+		pthread_mutex_unlock(&msg_lock);
+
+		/* wait until queue gets active or next message timeout expires */
+		pthread_mutex_lock(&msg_active_lock);
+
+		if (list_empty(&msg_list) == 0) {
+			tv.tv_sec = time(NULL) + EVENT_TIMEOUT_SEC - msg_age;
+			tv.tv_nsec = 0;
+			dbg("next event expires in %li seconds",
+			    EVENT_TIMEOUT_SEC - msg_age);
+			pthread_cond_timedwait(&msg_active, &msg_active_lock, &tv);
+		} else {
+			pthread_cond_wait(&msg_active, &msg_active_lock);
 		}
 
-		set_timeout(EVENT_TIMEOUT_SEC - msg_age);
-		return;
+		pthread_mutex_unlock(&msg_active_lock);
 	}
 }
 
-static int msg_add_queue(struct hotplug_msg *msg)
+/* every connect creates a thread which gets the msg, queues it and exits */
+static void *client_threads(void * parm)
 {
-	struct hotplug_msg *new_msg;
-	struct hotplug_msg *tmp_msg;
+	int sock;
+	struct hotplug_msg *msg;
+	int retval;
 
-	new_msg = malloc(sizeof(*new_msg));
-	if (new_msg == NULL) {
-		dbg("error malloc");
-		return -ENOMEM;
+	sock = (int) parm;
+	msg = msg_create();
+	if (msg == NULL) {
+		dbg("unable to store message");
+		goto exit;
 	}
-	memcpy(new_msg, msg, sizeof(*new_msg));
 
-	/* store timestamp of queuing */
-	new_msg->queue_time = time(NULL);
+	retval = recv(sock, msg, sizeof(struct hotplug_msg), 0);
+	if (retval <  0) {
+		dbg("unable to receive message");
+		goto exit;
+	}
 
-	/* sort message by sequence number into list*/
-	list_for_each_entry(tmp_msg, &msg_list, list)
-		if (tmp_msg->seqnum > new_msg->seqnum)
-			break;
-	list_add_tail(&new_msg->list, &tmp_msg->list);
+	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
+		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		goto exit;
+	}
 
-	return 0;
+	pthread_mutex_lock(&msg_lock);
+	msg_queue_insert(msg);
+	pthread_mutex_unlock(&msg_lock);
+
+exit:
+	close(sock);
+	pthread_exit(0);
 }
 
-static void work(void)
+int main(int argc, char *argv[])
 {
-	struct hotplug_msg *msg;
-	int msgid;
-	key_t key;
-	char buf[BUFFER_SIZE];
-	int ret;
-
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	msg = (struct hotplug_msg *) buf;
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("open message queue error");
+	pthread_t cli_tid;
+	pthread_t mgr_msg_tid;
+	pthread_t mgr_exec_tid;
+	int ssock;
+	int csock;
+	struct sockaddr_in saddr;
+	struct sockaddr_in caddr;
+	socklen_t clen;
+	int retval;
+
+	pthread_mutex_init(&msg_lock, NULL);
+	pthread_mutex_init(&msg_active_lock, NULL);
+	pthread_mutex_init(&exec_lock, NULL);
+	pthread_mutex_init(&exec_active_lock, NULL);
+	pthread_mutex_init(&running_lock, NULL);
+
+	ssock = socket(AF_INET, SOCK_STREAM, 0);
+	if (ssock == -1) {
+		dbg("error getting socket");
 		exit(1);
 	}
-	while (1) {
-		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
-		if (ret != -1) {
-			dbg("received sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
-			if (msg->seqnum >= expect_seqnum) {
-				msg_add_queue(msg);
-				msg_dump_queue();
-				msg_check_queue();
-				continue;
-			}
-			dbg("too late for event with sequence %d, event skipped ", msg->seqnum);
-		} else {
-			if (errno == EINTR) {
-				msg_check_queue();
-				msg_dump_queue();
-				delayed_check_queue();
-				delayed_dump_queue();
-				continue;
-			}
-			dbg("ipc message receive error '%s'", strerror(errno));
-		}
-	}
-}
 
-static int one_and_only(void)
-{
-	char string[100];
-
-	lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
-
-	/* see if we can open */
-	if (lock_file < 0)
-		return -1;
-	
-	/* see if we can lock */
-	if (lockf(lock_file, F_TLOCK, 0) < 0) {
-		close(lock_file);
-		return -1;
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sin_family = AF_INET;
+	saddr.sin_port = htons(UDEVD_PORT);
+	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	retval = bind(ssock, &saddr, sizeof(saddr));
+	if (retval < 0) {
+		dbg("bind failed\n");
+		goto exit;
 	}
 
-	snprintf(string, sizeof(string), "%d\n", getpid());
-	write(lock_file, string, strlen(string));
+	retval = listen(ssock, SOMAXCONN);
+	if (retval < 0) {
+		dbg("listen failed\n");
+		goto exit;
+	}
 
-	return 0;
-}
+	/* init queue management */
+	pthread_create(&mgr_msg_tid, NULL, msg_queue_manager, NULL);
+	pthread_create(&mgr_exec_tid, NULL, exec_queue_manager, NULL);
 
-int main(int argc, char *argv[])
-{
-	/* only let one version of the daemon run at any one time */
-	if (one_and_only() != 0)
-		exit(0);
-
-	/* set up signal handler */
-	signal(SIGINT, sig_handler);
-	signal(SIGTERM, sig_handler);
-	signal(SIGALRM, sig_handler);
-	signal(SIGCHLD, sig_handler);
+	clen = sizeof(caddr);
+	/* main loop */
+	while (1) {
+		csock = accept(ssock, &caddr, &clen);
+		if (csock < 0) {
+			if (errno == EINTR)
+				continue;
+			dbg("client accept failed\n");
+		}
 
-	work();
+		pthread_create(&cli_tid, NULL, client_threads, (void *) csock);
+	}
+exit:
+	close(ssock);
 	exit(0);
 }
===== udevd.h 1.4 vs edited =====
--- 1.4/udevd.h	Tue Jan 27 08:29:28 2004
+++ edited/udevd.h	Wed Jan 28 22:21:28 2004
@@ -23,16 +23,18 @@
 
 #include "list.h"
 
+#define UDEV_MAGIC			"udev_" UDEV_VERSION
 #define FIRST_EVENT_TIMEOUT_SEC		1
-#define EVENT_TIMEOUT_SEC		5
-#define UDEVSEND_RETRY_COUNT		50 /* x 10 millisec */
+#define EVENT_TIMEOUT_SEC		10
+#define UDEVD_START_TIMEOUT		20 /* x 100 millisec */
+#define UDEVD_PORT			44444
 
 #define IPC_KEY_ID			1
 #define HOTPLUGMSGTYPE			44
 
 
 struct hotplug_msg {
-	long mtype;
+	char magic[20];
 	struct list_head list;
 	pid_t pid;
 	int seqnum;
===== udevsend.c 1.8 vs edited =====
--- 1.8/udevsend.c	Tue Jan 27 08:29:28 2004
+++ edited/udevsend.c	Wed Jan 28 22:21:28 2004
@@ -32,12 +32,29 @@
 #include <unistd.h>
 #include <time.h>
 #include <wait.h>
+#include <netinet/in.h>
 
 #include "udev.h"
 #include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
+
+static void sig_handler(int signum)
+{
+	switch (signum) {
+		case SIGALRM:
+			dbg("timeout");
+		case SIGINT:
+		case SIGTERM:
+			exit(20 + signum);
+			break;
+		default:
+			dbg("unhandled signal");
+	}
+}
+
+
 static inline char *get_action(void)
 {
 	char *action;
@@ -46,6 +63,7 @@
 	return action;
 }
 
+
 static inline char *get_devpath(void)
 {
 	char *devpath;
@@ -54,6 +72,7 @@
 	return devpath;
 }
 
+
 static inline char *get_seqnum(void)
 {
 	char *seqnum;
@@ -62,11 +81,12 @@
 	return seqnum;
 }
 
+
 static int build_hotplugmsg(struct hotplug_msg *msg, char *action,
 			    char *devpath, char *subsystem, int seqnum)
 {
 	memset(msg, 0x00, sizeof(*msg));
-	msg->mtype = HOTPLUGMSGTYPE;
+	strfieldcpy(msg->magic, UDEV_MAGIC);
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
 	strncpy(msg->devpath, devpath, 128);
@@ -74,6 +94,7 @@
 	return sizeof(struct hotplug_msg);
 }
 
+
 static int start_daemon(void)
 {
 	pid_t pid;
@@ -111,9 +132,6 @@
 
 int main(int argc, char* argv[])
 {
-	int msgid;
-	key_t key;
-	struct msqid_ds msg_queue;
 	struct hotplug_msg message;
 	char *action;
 	char *devpath;
@@ -124,6 +142,8 @@
 	int size;
 	int loop;
 	struct timespec tspec;
+	int sock;
+	struct sockaddr_in saddr;
 
 	subsystem = argv[1];
 	if (subsystem == NULL) {
@@ -150,41 +170,62 @@
 	}
 	seq = atoi(seqnum);
 
-	/* create ipc message queue or get id of our existing one */
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	dbg("using ipc queue 0x%0x", key);
-	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("error open ipc queue");
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock == -1) {
+		dbg("error getting socket");
 		goto exit;
 	}
 
-	/* send ipc message to the daemon */
-	retval = msgsnd(msgid, &message, size, 0);
-	if (retval == -1) {
-		dbg("error sending ipc message");
-		goto exit;
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sin_family = AF_INET;
+	saddr.sin_port = htons(UDEVD_PORT);
+	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	signal(SIGINT, sig_handler);
+	signal(SIGTERM, sig_handler);
+	signal(SIGALRM, sig_handler);
+
+	/* try to connect, if it fails start daemon */
+	retval = connect(sock, &saddr, sizeof(saddr));
+	if (retval != -1) {
+		goto send;
+	} else {
+		dbg("connect failed, try starting daemon...");
+		retval = start_daemon();
+		if (retval == 0) {
+			dbg("daemon started");
+		} else {
+			dbg("error starting daemon");
+			goto exit;
+		}
 	}
 
-	/* get state of ipc queue */
+	/* try to connect while daemon to starts */
 	tspec.tv_sec = 0;
-	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = UDEVSEND_RETRY_COUNT;
+	tspec.tv_nsec = 100000000;  /* 100 millisec */
+	loop = UDEVD_START_TIMEOUT;
 	while (loop--) {
-		retval = msgctl(msgid, IPC_STAT, &msg_queue);
-		if (retval == -1) {
-			dbg("error getting info on ipc queue");
-			goto exit;
-		}
-		if (msg_queue.msg_qnum == 0)
-			goto exit;
+		retval = connect(sock, &saddr, sizeof(saddr));
+		if (retval != -1)
+			goto send;
+		else
+			dbg("retry to connect %d", UDEVD_START_TIMEOUT - loop);
 		nanosleep(&tspec, NULL);
 	}
+	dbg("error connecting to daemon, start daemon failed");
+	goto exit;
 
-	info("message is still in the ipc queue, starting daemon...");
-	retval = start_daemon();
+send:
+	size = build_hotplugmsg(&message, action, devpath, subsystem, seq);
+	retval = send(sock, &message, size, 0);
+	if (retval == -1) {
+		dbg("error sending message");
+		close (sock);
+		goto exit;
+	}
+	close (sock);
+	return 0;
 
 exit:
-	return retval;
+	return 1;
 }
===== test/udevd_test.sh 1.4 vs edited =====
--- 1.4/test/udevd_test.sh	Tue Jan 27 08:29:28 2004
+++ edited/test/udevd_test.sh	Wed Jan 28 22:23:22 2004
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # kill daemon, first event will start it again
-killall udevd
+#killall udevd
 
 # 3 x connect/disconnect sequence of sda/sdb/sdc
 

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (10 preceding siblings ...)
  2004-01-28 21:47 ` Kay Sievers
@ 2004-01-29  1:52 ` Kay Sievers
  2004-01-29  1:56 ` Kay Sievers
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-29  1:52 UTC (permalink / raw)
  To: linux-hotplug

On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote:
> On Tue, Jan 27, 2004 at 11:13:09AM -0800, Greg KH wrote:
> > On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> > > On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > > > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > > > >   1. We are much too slow.
> > > > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > > > >      working on the same devpath.
> > > > > > > 
> > > > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > > > for each one to finish, right?
> > > > > > 
> > > > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > > > pid. So we can search the queue if we are already working on this devpath,
> > > > > > and delay the new exec until the former exec comes back.
> > > > > 
> > > > > Ok, if that isn't too much trouble.
> > > > > 
> > > > > > Is it feasible to run in parallel for different paths, or can you think
> > > > > > of any problem?
> > > > > 
> > > > > I can't think of any problem with that.
> > > > 
> > > > Here is the next round. We have three queues now. All incoming messages
> > > > are queued in msg_list and if nothing is missing we move it to the
> > > > running_list and exec in the background.
> > > > If the exec comes back, it removes the message from the running_list and
> > > > frees the message.
> > > > 
> > > > Before we exec, we check the running_list if there is a udev running on
> > > > the same device path. If yes, we move the message to the delay_list. If
> > > > the former exec comes back, we move the message to the running_list and
> > > > exec it.
> > > 
> > > Oh, sorry forget about it now.
> > > I will come up with something better tested.
> > 
> > Oops, I just applied this version :)
> > 
> > I'll try testing this later on today.
> 
> Oh, couldn't resist to try threads.
> It's a multithreaded udevd that communicates through a localhost socket.
> The message includes a magic with the udev version, so we don't accept
> older udevsend's.
> 
> No need for locking, cause we can't bind two sockets on the same address.
> The daemon tries to connect and if it fails it starts the daemon.
> 
> We create a thread for every incoming connection, handle over the socket,
> sort the messages in the global message queue and exit the thread.
> Huh, that was easy with threads :)
> 
> With the addition of a message we wakeup the queue manager thread and
> handle timeouts or move the message to the global exec list. This wakes
> up the exec list manager who looks if a process is already running for this
> device path.
> If yes, the exec is delayed otherwise we create a thread that execs udev.
> n the background. With the return of udev we free the message and wakeup
> the exec list manager to look if something is pending.
> 
> It is just a quick shot, cause I couldn't solve the problems with fork an
> scheduling and I wanted to see if I'm to stupid  :)
> But if anybody with a better idea or more experience with I/O scheduling
> we may go another way. The remaining problem is that klibc doesn't support
> threads.
> 
> By now, we don't exec anything, it's just a sleep 3 for every exec,
> but you can see the queue management by watching syslog and do:
> 
>   DEVPATH=/abc ACTION­d SEQNUM=0 ./udevsend /abc

Here is the next version, that also does the exec.
Please have a look.

thanks,
Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (11 preceding siblings ...)
  2004-01-29  1:52 ` Kay Sievers
@ 2004-01-29  1:56 ` Kay Sievers
  2004-01-29 15:55 ` Kay Sievers
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-29  1:56 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 3932 bytes --]

On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote:
> On Tue, Jan 27, 2004 at 11:13:09AM -0800, Greg KH wrote:
> > On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> > > On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > > > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > > > >   1. We are much too slow.
> > > > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > > > >      working on the same devpath.
> > > > > > > 
> > > > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > > > for each one to finish, right?
> > > > > > 
> > > > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > > > pid. So we can search the queue if we are already working on this devpath,
> > > > > > and delay the new exec until the former exec comes back.
> > > > > 
> > > > > Ok, if that isn't too much trouble.
> > > > > 
> > > > > > Is it feasible to run in parallel for different paths, or can you think
> > > > > > of any problem?
> > > > > 
> > > > > I can't think of any problem with that.
> > > > 
> > > > Here is the next round. We have three queues now. All incoming messages
> > > > are queued in msg_list and if nothing is missing we move it to the
> > > > running_list and exec in the background.
> > > > If the exec comes back, it removes the message from the running_list and
> > > > frees the message.
> > > > 
> > > > Before we exec, we check the running_list if there is a udev running on
> > > > the same device path. If yes, we move the message to the delay_list. If
> > > > the former exec comes back, we move the message to the running_list and
> > > > exec it.
> > > 
> > > Oh, sorry forget about it now.
> > > I will come up with something better tested.
> > 
> > Oops, I just applied this version :)
> > 
> > I'll try testing this later on today.
> 
> Oh, couldn't resist to try threads.
> It's a multithreaded udevd that communicates through a localhost socket.
> The message includes a magic with the udev version, so we don't accept
> older udevsend's.
> 
> No need for locking, cause we can't bind two sockets on the same address.
> The daemon tries to connect and if it fails it starts the daemon.
> 
> We create a thread for every incoming connection, handle over the socket,
> sort the messages in the global message queue and exit the thread.
> Huh, that was easy with threads :)
> 
> With the addition of a message we wakeup the queue manager thread and
> handle timeouts or move the message to the global exec list. This wakes
> up the exec list manager who looks if a process is already running for this
> device path.
> If yes, the exec is delayed otherwise we create a thread that execs udev.
> n the background. With the return of udev we free the message and wakeup
> the exec list manager to look if something is pending.
> 
> It is just a quick shot, cause I couldn't solve the problems with fork an
> scheduling and I wanted to see if I'm to stupid  :)
> But if anybody with a better idea or more experience with I/O scheduling
> we may go another way. The remaining problem is that klibc doesn't support
> threads.
> 
> By now, we don't exec anything, it's just a sleep 3 for every exec,
> but you can see the queue management by watching syslog and do:
> 
>   DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc

Sorry, on my keyboard 'a' and 'y' are direct neighbours :)

thanks,
Kay

[-- Attachment #2: 01-udevd-threads.patch --]
[-- Type: text/plain, Size: 20044 bytes --]

===== Makefile 1.93 vs edited =====
--- 1.93/Makefile	Tue Jan 27 08:29:28 2004
+++ edited/Makefile	Wed Jan 28 22:21:26 2004
@@ -255,7 +255,7 @@
 	$(STRIPCMD) $@
 
 $(DAEMON): udevd.h udevd.o udevd.o logging.o
-	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
+	$(LD) $(LDFLAGS) -lpthread -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $@
 
 $(SENDER): udevd.h udevsend.o udevd.o logging.o
===== udevd.c 1.7 vs edited =====
--- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
+++ edited/udevd.c	Thu Jan 29 02:41:13 2004
@@ -3,7 +3,6 @@
  *
  * Userspace devfs
  *
- * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
@@ -24,7 +23,6 @@
 
 #include <stddef.h>
 #include <sys/types.h>
-#include <sys/ipc.h>
 #include <sys/wait.h>
 #include <sys/msg.h>
 #include <signal.h>
@@ -35,6 +33,11 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <pthread.h>
 
 #include "list.h"
 #include "udev.h"
@@ -43,141 +46,85 @@
 #include "logging.h"
 
 
-#define BUFFER_SIZE			1024
+static pthread_mutex_t  msg_lock;
+static pthread_mutex_t  msg_active_lock;
+static pthread_cond_t msg_active;
+
+static pthread_mutex_t  exec_lock;
+static pthread_mutex_t  exec_active_lock;
+static pthread_cond_t exec_active;
 
-static int running_remove_queue(pid_t pid);
-static int msg_exec(struct hotplug_msg *msg);
+static pthread_mutex_t  running_lock;
 
-static int expect_seqnum = 0;
-static int lock_file = -1;
-static char *lock_filename = ".udevd_lock";
+static int expected_seqnum = 0;
 
 LIST_HEAD(msg_list);
+LIST_HEAD(exec_list);
 LIST_HEAD(running_list);
-LIST_HEAD(delayed_list);
 
-static void sig_handler(int signum)
-{
-	pid_t pid;
-
-	dbg("caught signal %d", signum);
-	switch (signum) {
-	case SIGALRM:
-		dbg("event timeout reached");
-		break;
-	case SIGCHLD:
-		/* catch signals from exiting childs */
-		while ( (pid = waitpid(-1, NULL, WNOHANG)) > 0) {
-			dbg("exec finished, pid %d", pid);
-			running_remove_queue(pid);
-		}
-		break;
-	case SIGINT:
-	case SIGTERM:
-		if (lock_file >= 0) {
-			close(lock_file);
-			unlink(lock_filename);
-		}
-		exit(20 + signum);
-		break;
-	default:
-		dbg("unhandled signal");
-	}
-}
 
-static void set_timeout(int seconds)
+static void msg_dump_queue(void)
 {
-	alarm(seconds);
-	dbg("set timeout in %d seconds", seconds);
-}
+	struct hotplug_msg *msg;
 
-static int running_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move sequence %d [%d] to running queue '%s'",
-	    msg->seqnum, msg->pid, msg->devpath);
-	list_move_tail(&msg->list, &running_list);
-	return 0;
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static int running_remove_queue(pid_t  pid)
+static void msg_dump(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
-
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (child->pid == pid) {
-			list_del_init(&child->list);
-			free(child);
-			return 0;
-		}
-	return -EINVAL;
+	dbg("sequence %d, '%s', '%s', '%s'",
+	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static pid_t running_getpid_by_devpath(struct hotplug_msg *msg)
+/* allocates a new message */
+static struct hotplug_msg *msg_create(void)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
+	struct hotplug_msg *new_msg;
 
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (strncmp(child->devpath, msg->devpath, sizeof(child->devpath)) == 0)
-			return child->pid;
-	return 0;
+	new_msg = malloc(sizeof(struct hotplug_msg));
+	if (new_msg == NULL) {
+		dbg("error malloc");
+		return NULL;
+	}
+	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
+	return new_msg;
 }
 
-static void delayed_dump_queue(void)
+/* orders the message in the queue by sequence number */
+static void msg_queue_insert(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
+	struct hotplug_msg *loop_msg;
 
-	list_for_each_entry(child, &delayed_list, list)
-		dbg("event for '%s' in queue", child->devpath);
-}
+	dbg("add message seq %d", msg->seqnum);
 
-static int delayed_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move event to delayed queue '%s'", msg->devpath);
-	list_move_tail(&msg->list, &delayed_list);
-	return 0;
-}
+	/* sort message by sequence number into list*/
+	list_for_each_entry(loop_msg, &msg_list, list)
+		if (loop_msg->seqnum > msg->seqnum)
+			break;
+	list_add_tail(&msg->list, &loop_msg->list);
 
-static void delayed_check_queue(void)
-{
-	struct hotplug_msg *delayed_child;
-	struct hotplug_msg *running_child;
-	struct hotplug_msg *tmp_child;
-
-	/* see if we have delayed exec's that can run now */
-	list_for_each_entry_safe(delayed_child, tmp_child, &delayed_list, list)
-		list_for_each_entry_safe(running_child, tmp_child, &running_list, list)
-			if (strncmp(delayed_child->devpath, running_child->devpath,
-			    sizeof(running_child->devpath)) == 0) {
-				dbg("delayed exec for '%s' can run now", delayed_child->devpath);
-				msg_exec(delayed_child);
-			}
-}
+	/* store timestamp of queuing */
+	msg->queue_time = time(NULL);
 
-static void msg_dump(struct hotplug_msg *msg)
-{
-	dbg("sequence %d, '%s', '%s', '%s'",
-	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&msg_active_lock);
+	pthread_cond_signal(&msg_active);
+	pthread_mutex_unlock(&msg_active_lock);
+
+	return ;
 }
 
-static int msg_exec(struct hotplug_msg *msg)
+/* forks event and removes event from run queue when finished */
+static void *run_threads(void * parm)
 {
 	pid_t pid;
+	struct hotplug_msg *msg;
 
-	msg_dump(msg);
-
+	msg = parm;
 	setenv("ACTION", msg->action, 1);
 	setenv("DEVPATH", msg->devpath, 1);
 
-	/* delay exec, if we already have a udev working on the same devpath */
-	pid = running_getpid_by_devpath(msg);
-	if (pid != 0) {
-		dbg("delay exec of sequence %d, [%d] already working on '%s'",
-		    msg->seqnum, pid, msg->devpath);
-		delayed_moveto_queue(msg);
-	}
-
 	pid = fork();
 	switch (pid) {
 	case 0:
@@ -188,157 +135,246 @@
 		break;
 	case -1:
 		dbg("fork of child failed");
-		return -1;
+		goto exit;
 	default:
-		/* exec in background, get the SIGCHLD with the sig handler */
-		msg->pid = pid;
-		running_moveto_queue(msg);
-		break;
+		/* wait for exit of child */
+		dbg("==> exec seq %d [%d] working at '%s'",
+		    msg->seqnum, pid, msg->devpath);
+		wait(NULL);
+		dbg("<== exec seq %d came back", msg->seqnum);
 	}
-	return 0;
+
+exit:
+	/* remove event from run list */
+	pthread_mutex_lock(&running_lock);
+	list_del_init(&msg->list);
+	pthread_mutex_unlock(&running_lock);
+
+	free(msg);
+
+	/* signal queue activity to exec manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+
+	pthread_exit(0);
 }
 
-static void msg_dump_queue(void)
+/* returns already running task with devpath */
+static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
 
-	list_for_each_entry(msg, &msg_list, list)
-		dbg("sequence %d in queue", msg->seqnum);
+	list_for_each_entry_safe(loop_msg, tmp_msg, &running_list, list)
+		if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
+			return loop_msg;
+	return NULL;
 }
 
-static void msg_check_queue(void)
+/* queue management executes the events and delays events for the same devpath */
+static void *exec_queue_manager(void * parm)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
 	struct hotplug_msg *tmp_msg;
-	time_t msg_age;
+	struct hotplug_msg *msg;
+	pthread_t run_tid;
 
-recheck:
-	/* dispatch events until one is missing */
-	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
-		if (msg->seqnum != expect_seqnum)
-			break;
-		msg_exec(msg);
-		expect_seqnum++;
-	}
+	while (1) {
+		dbg("exec list manager");
+		pthread_mutex_lock(&exec_lock);
 
-	/* recalculate next timeout */
-	if (list_empty(&msg_list) == 0) {
-		msg_age = time(NULL) - msg->queue_time;
-		if (msg_age > EVENT_TIMEOUT_SEC-1) {
-			info("event %d, age %li seconds, skip event %d-%d",
-			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
-			expect_seqnum = msg->seqnum;
-			goto recheck;
+		list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, list) {
+			msg = running_with_devpath(loop_msg);
+			if (msg == NULL) {
+				/* move event to run list */
+				pthread_mutex_lock(&running_lock);
+				list_move_tail(&loop_msg->list, &running_list);
+				pthread_mutex_unlock(&running_lock);
+
+				pthread_create(&run_tid, NULL, run_threads, (void *) loop_msg);
+				pthread_detach(run_tid);
+
+				dbg("moved seq %d to running list", loop_msg->seqnum);
+			} else {
+				dbg("delay seq %d, cause seq %d already working on '%s'",
+				    loop_msg->seqnum, msg->seqnum, msg->devpath);
+			}
 		}
 
-		/* the first sequence gets its own timeout */
-		if (expect_seqnum == 0) {
-			msg_age = EVENT_TIMEOUT_SEC - FIRST_EVENT_TIMEOUT_SEC;
-			expect_seqnum = 1;
-		}
+		pthread_mutex_unlock(&exec_lock);
 
-		set_timeout(EVENT_TIMEOUT_SEC - msg_age);
-		return;
+		/* wait for activation, new events or childs coming back */
+		pthread_mutex_lock(&exec_active_lock);
+		pthread_cond_wait(&exec_active, &exec_active_lock);
+		pthread_mutex_unlock(&exec_active_lock);
 	}
 }
 
-static int msg_add_queue(struct hotplug_msg *msg)
+/* move message from incoming to exec queue */
+static void msg_move_exec(struct list_head *head)
 {
-	struct hotplug_msg *new_msg;
-	struct hotplug_msg *tmp_msg;
-
-	new_msg = malloc(sizeof(*new_msg));
-	if (new_msg == NULL) {
-		dbg("error malloc");
-		return -ENOMEM;
-	}
-	memcpy(new_msg, msg, sizeof(*new_msg));
-
-	/* store timestamp of queuing */
-	new_msg->queue_time = time(NULL);
-
-	/* sort message by sequence number into list*/
-	list_for_each_entry(tmp_msg, &msg_list, list)
-		if (tmp_msg->seqnum > new_msg->seqnum)
-			break;
-	list_add_tail(&new_msg->list, &tmp_msg->list);
-
-	return 0;
+	list_move_tail(head, &exec_list);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
 }
 
-static void work(void)
+/* queue management thread handles the timeouts and dispatches the events */
+static void *msg_queue_manager(void * parm)
 {
-	struct hotplug_msg *msg;
-	int msgid;
-	key_t key;
-	char buf[BUFFER_SIZE];
-	int ret;
-
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	msg = (struct hotplug_msg *) buf;
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("open message queue error");
-		exit(1);
-	}
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
+	time_t msg_age = 0;
+	struct timespec tv;
+
 	while (1) {
-		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
-		if (ret != -1) {
-			dbg("received sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
-			if (msg->seqnum >= expect_seqnum) {
-				msg_add_queue(msg);
-				msg_dump_queue();
-				msg_check_queue();
+		dbg("msg queue manager, next expected is %d", expected_seqnum);
+		pthread_mutex_lock(&msg_lock);
+		pthread_mutex_lock(&exec_lock);
+
+recheck:
+		list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, list) {
+			/* move event with expected sequence to the exec list */
+			if (loop_msg->seqnum == expected_seqnum) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum++;
+				dbg("moved seq %d to exec, next expected is %d",
+				    loop_msg->seqnum, expected_seqnum);
 				continue;
 			}
-			dbg("too late for event with sequence %d, event skipped ", msg->seqnum);
-		} else {
-			if (errno == EINTR) {
-				msg_check_queue();
-				msg_dump_queue();
-				delayed_check_queue();
-				delayed_dump_queue();
-				continue;
+
+			/* move event with expired timeout to the exec list */
+			msg_age = time(NULL) - loop_msg->queue_time;
+			if (msg_age > EVENT_TIMEOUT_SEC-1) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum = loop_msg->seqnum+1;
+				dbg("moved seq %d to exec, reset next expected to %d",
+				    loop_msg->seqnum, expected_seqnum);
+				goto recheck;
+			} else {
+				break;
 			}
-			dbg("ipc message receive error '%s'", strerror(errno));
 		}
+
+		msg_dump_queue();
+		pthread_mutex_unlock(&exec_lock);
+		pthread_mutex_unlock(&msg_lock);
+
+		/* wait until queue gets active or next message timeout expires */
+		pthread_mutex_lock(&msg_active_lock);
+
+		if (list_empty(&msg_list) == 0) {
+			tv.tv_sec = time(NULL) + EVENT_TIMEOUT_SEC - msg_age;
+			tv.tv_nsec = 0;
+			dbg("next event expires in %li seconds",
+			    EVENT_TIMEOUT_SEC - msg_age);
+			pthread_cond_timedwait(&msg_active, &msg_active_lock, &tv);
+		} else {
+			pthread_cond_wait(&msg_active, &msg_active_lock);
+		}
+
+		pthread_mutex_unlock(&msg_active_lock);
 	}
 }
 
-static int one_and_only(void)
+/* every connect creates a thread which gets the msg, queues it and exits */
+static void *client_threads(void * parm)
 {
-	char string[100];
+	int sock;
+	struct hotplug_msg *msg;
+	int retval;
 
-	lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
+	sock = (int) parm;
 
-	/* see if we can open */
-	if (lock_file < 0)
-		return -1;
-	
-	/* see if we can lock */
-	if (lockf(lock_file, F_TLOCK, 0) < 0) {
-		close(lock_file);
-		return -1;
+	msg = msg_create();
+	if (msg == NULL) {
+		dbg("unable to store message");
+		goto exit;
 	}
 
-	snprintf(string, sizeof(string), "%d\n", getpid());
-	write(lock_file, string, strlen(string));
+	retval = recv(sock, msg, sizeof(struct hotplug_msg), 0);
+	if (retval <  0) {
+		dbg("unable to receive message");
+		goto exit;
+	}
 
-	return 0;
+	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
+		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		goto exit;
+	}
+
+	pthread_mutex_lock(&msg_lock);
+	msg_queue_insert(msg);
+	pthread_mutex_unlock(&msg_lock);
+
+exit:
+	close(sock);
+	pthread_exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-	/* only let one version of the daemon run at any one time */
-	if (one_and_only() != 0)
-		exit(0);
-
-	/* set up signal handler */
-	signal(SIGINT, sig_handler);
-	signal(SIGTERM, sig_handler);
-	signal(SIGALRM, sig_handler);
-	signal(SIGCHLD, sig_handler);
+	pthread_t cli_tid;
+	pthread_t mgr_msg_tid;
+	pthread_t mgr_exec_tid;
+	int ssock;
+	int csock;
+	struct sockaddr_in saddr;
+	struct sockaddr_in caddr;
+	socklen_t clen;
+	int retval;
+
+	pthread_mutex_init(&msg_lock, NULL);
+	pthread_mutex_init(&msg_active_lock, NULL);
+	pthread_mutex_init(&exec_lock, NULL);
+	pthread_mutex_init(&exec_active_lock, NULL);
+	pthread_mutex_init(&running_lock, NULL);
+
+	ssock = socket(AF_INET, SOCK_STREAM, 0);
+	if (ssock == -1) {
+		dbg("error getting socket");
+		exit(1);
+	}
+
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sin_family = AF_INET;
+	saddr.sin_port = htons(UDEVD_PORT);
+	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	retval = bind(ssock, &saddr, sizeof(saddr));
+	if (retval < 0) {
+		dbg("bind failed\n");
+		goto exit;
+	}
+
+	retval = listen(ssock, SOMAXCONN);
+	if (retval < 0) {
+		dbg("listen failed\n");
+		goto exit;
+	}
 
-	work();
+	/* init queue management */
+	pthread_create(&mgr_msg_tid, NULL, msg_queue_manager, NULL);
+	pthread_detach(mgr_msg_tid);
+	pthread_create(&mgr_exec_tid, NULL, exec_queue_manager, NULL);
+	pthread_detach(mgr_exec_tid);
+
+	clen = sizeof(caddr);
+	/* main loop */
+	while (1) {
+		csock = accept(ssock, &caddr, &clen);
+		if (csock < 0) {
+			if (errno == EINTR)
+				continue;
+			dbg("client accept failed\n");
+		}
+
+		pthread_create(&cli_tid, NULL, client_threads, (void *) csock);
+		pthread_detach(cli_tid);
+	}
+exit:
+	close(ssock);
 	exit(0);
 }
===== udevd.h 1.4 vs edited =====
--- 1.4/udevd.h	Tue Jan 27 08:29:28 2004
+++ edited/udevd.h	Thu Jan 29 01:53:30 2004
@@ -23,16 +23,17 @@
 
 #include "list.h"
 
-#define FIRST_EVENT_TIMEOUT_SEC		1
+#define UDEV_MAGIC			"udev_" UDEV_VERSION
 #define EVENT_TIMEOUT_SEC		5
-#define UDEVSEND_RETRY_COUNT		50 /* x 10 millisec */
+#define UDEVD_START_TIMEOUT		20 /* x 100 millisec */
+#define UDEVD_PORT			44444
 
 #define IPC_KEY_ID			1
 #define HOTPLUGMSGTYPE			44
 
 
 struct hotplug_msg {
-	long mtype;
+	char magic[20];
 	struct list_head list;
 	pid_t pid;
 	int seqnum;
===== udevsend.c 1.8 vs edited =====
--- 1.8/udevsend.c	Tue Jan 27 08:29:28 2004
+++ edited/udevsend.c	Thu Jan 29 02:44:51 2004
@@ -32,12 +32,14 @@
 #include <unistd.h>
 #include <time.h>
 #include <wait.h>
+#include <netinet/in.h>
 
 #include "udev.h"
 #include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
+
 static inline char *get_action(void)
 {
 	char *action;
@@ -66,7 +68,7 @@
 			    char *devpath, char *subsystem, int seqnum)
 {
 	memset(msg, 0x00, sizeof(*msg));
-	msg->mtype = HOTPLUGMSGTYPE;
+	strfieldcpy(msg->magic, UDEV_MAGIC);
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
 	strncpy(msg->devpath, devpath, 128);
@@ -108,12 +110,8 @@
 	return 0;
 }
 
-
 int main(int argc, char* argv[])
 {
-	int msgid;
-	key_t key;
-	struct msqid_ds msg_queue;
 	struct hotplug_msg message;
 	char *action;
 	char *devpath;
@@ -124,6 +122,8 @@
 	int size;
 	int loop;
 	struct timespec tspec;
+	int sock;
+	struct sockaddr_in saddr;
 
 	subsystem = argv[1];
 	if (subsystem == NULL) {
@@ -150,41 +150,58 @@
 	}
 	seq = atoi(seqnum);
 
-	/* create ipc message queue or get id of our existing one */
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	dbg("using ipc queue 0x%0x", key);
-	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("error open ipc queue");
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock == -1) {
+		dbg("error getting socket");
 		goto exit;
 	}
 
-	/* send ipc message to the daemon */
-	retval = msgsnd(msgid, &message, size, 0);
-	if (retval == -1) {
-		dbg("error sending ipc message");
-		goto exit;
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sin_family = AF_INET;
+	saddr.sin_port = htons(UDEVD_PORT);
+	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	/* try to connect, if it fails start daemon */
+	retval = connect(sock, &saddr, sizeof(saddr));
+	if (retval != -1) {
+		goto send;
+	} else {
+		dbg("connect failed, try starting daemon...");
+		retval = start_daemon();
+		if (retval == 0) {
+			dbg("daemon started");
+		} else {
+			dbg("error starting daemon");
+			goto exit;
+		}
 	}
 
-	/* get state of ipc queue */
+	/* try to connect while daemon to starts */
 	tspec.tv_sec = 0;
-	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = UDEVSEND_RETRY_COUNT;
+	tspec.tv_nsec = 100000000;  /* 100 millisec */
+	loop = UDEVD_START_TIMEOUT;
 	while (loop--) {
-		retval = msgctl(msgid, IPC_STAT, &msg_queue);
-		if (retval == -1) {
-			dbg("error getting info on ipc queue");
-			goto exit;
-		}
-		if (msg_queue.msg_qnum == 0)
-			goto exit;
+		retval = connect(sock, &saddr, sizeof(saddr));
+		if (retval != -1)
+			goto send;
+		else
+			dbg("retry to connect %d", UDEVD_START_TIMEOUT - loop);
 		nanosleep(&tspec, NULL);
 	}
+	dbg("error connecting to daemon, start daemon failed");
+	goto exit;
 
-	info("message is still in the ipc queue, starting daemon...");
-	retval = start_daemon();
+send:
+	size = build_hotplugmsg(&message, action, devpath, subsystem, seq);
+	retval = send(sock, &message, size, 0);
+	if (retval == -1) {
+		dbg("error sending message");
+		close (sock);
+		goto exit;
+	}
+	close (sock);
+	return 0;
 
 exit:
-	return retval;
+	return 1;
 }
===== test/udevd_test.sh 1.4 vs edited =====
--- 1.4/test/udevd_test.sh	Tue Jan 27 08:29:28 2004
+++ edited/test/udevd_test.sh	Wed Jan 28 22:23:22 2004
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # kill daemon, first event will start it again
-killall udevd
+#killall udevd
 
 # 3 x connect/disconnect sequence of sda/sdb/sdc
 

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (12 preceding siblings ...)
  2004-01-29  1:56 ` Kay Sievers
@ 2004-01-29 15:55 ` Kay Sievers
  2004-01-31  2:42 ` Kay Sievers
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-29 15:55 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 4135 bytes --]

On Thu, Jan 29, 2004 at 02:56:25AM +0100, Kay Sievers wrote:
> On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote:
> > On Tue, Jan 27, 2004 at 11:13:09AM -0800, Greg KH wrote:
> > > On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> > > > On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > > > > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > > > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > > > > >   1. We are much too slow.
> > > > > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > > > > >      working on the same devpath.
> > > > > > > > 
> > > > > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > > > > for each one to finish, right?
> > > > > > > 
> > > > > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > > > > pid. So we can search the queue if we are already working on this devpath,
> > > > > > > and delay the new exec until the former exec comes back.
> > > > > > 
> > > > > > Ok, if that isn't too much trouble.
> > > > > > 
> > > > > > > Is it feasible to run in parallel for different paths, or can you think
> > > > > > > of any problem?
> > > > > > 
> > > > > > I can't think of any problem with that.
> > > > > 
> > > > > Here is the next round. We have three queues now. All incoming messages
> > > > > are queued in msg_list and if nothing is missing we move it to the
> > > > > running_list and exec in the background.
> > > > > If the exec comes back, it removes the message from the running_list and
> > > > > frees the message.
> > > > > 
> > > > > Before we exec, we check the running_list if there is a udev running on
> > > > > the same device path. If yes, we move the message to the delay_list. If
> > > > > the former exec comes back, we move the message to the running_list and
> > > > > exec it.
> > > > 
> > > > Oh, sorry forget about it now.
> > > > I will come up with something better tested.
> > > 
> > > Oops, I just applied this version :)
> > > 
> > > I'll try testing this later on today.
> > 
> > Oh, couldn't resist to try threads.
> > It's a multithreaded udevd that communicates through a localhost socket.
> > The message includes a magic with the udev version, so we don't accept
> > older udevsend's.
> > 
> > No need for locking, cause we can't bind two sockets on the same address.
> > The daemon tries to connect and if it fails it starts the daemon.
> > 
> > We create a thread for every incoming connection, handle over the socket,
> > sort the messages in the global message queue and exit the thread.
> > Huh, that was easy with threads :)
> > 
> > With the addition of a message we wakeup the queue manager thread and
> > handle timeouts or move the message to the global exec list. This wakes
> > up the exec list manager who looks if a process is already running for this
> > device path.
> > If yes, the exec is delayed otherwise we create a thread that execs udev.
> > n the background. With the return of udev we free the message and wakeup
> > the exec list manager to look if something is pending.
> > 
> > It is just a quick shot, cause I couldn't solve the problems with fork an
> > scheduling and I wanted to see if I'm to stupid  :)
> > But if anybody with a better idea or more experience with I/O scheduling
> > we may go another way. The remaining problem is that klibc doesn't support
> > threads.
> > 
> > By now, we don't exec anything, it's just a sleep 3 for every exec,
> > but you can see the queue management by watching syslog and do:
> > 
> >   DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc

Next version, switched to unix domain sockets.

thanks,
Kay

[-- Attachment #2: 01-udevd-threads.patch --]
[-- Type: text/plain, Size: 20332 bytes --]

===== Makefile 1.93 vs edited =====
--- 1.93/Makefile	Tue Jan 27 08:29:28 2004
+++ edited/Makefile	Wed Jan 28 22:21:26 2004
@@ -255,7 +255,7 @@
 	$(STRIPCMD) $@
 
 $(DAEMON): udevd.h udevd.o udevd.o logging.o
-	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
+	$(LD) $(LDFLAGS) -lpthread -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $@
 
 $(SENDER): udevd.h udevsend.o udevd.o logging.o
===== udevd.c 1.7 vs edited =====
--- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
+++ edited/udevd.c	Thu Jan 29 16:40:58 2004
@@ -3,7 +3,6 @@
  *
  * Userspace devfs
  *
- * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
@@ -24,7 +23,6 @@
 
 #include <stddef.h>
 #include <sys/types.h>
-#include <sys/ipc.h>
 #include <sys/wait.h>
 #include <sys/msg.h>
 #include <signal.h>
@@ -35,6 +33,10 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
 
 #include "list.h"
 #include "udev.h"
@@ -43,141 +45,85 @@
 #include "logging.h"
 
 
-#define BUFFER_SIZE			1024
+static pthread_mutex_t  msg_lock;
+static pthread_mutex_t  msg_active_lock;
+static pthread_cond_t msg_active;
+
+static pthread_mutex_t  exec_lock;
+static pthread_mutex_t  exec_active_lock;
+static pthread_cond_t exec_active;
 
-static int running_remove_queue(pid_t pid);
-static int msg_exec(struct hotplug_msg *msg);
+static pthread_mutex_t  running_lock;
 
-static int expect_seqnum = 0;
-static int lock_file = -1;
-static char *lock_filename = ".udevd_lock";
+static int expected_seqnum = 0;
 
 LIST_HEAD(msg_list);
+LIST_HEAD(exec_list);
 LIST_HEAD(running_list);
-LIST_HEAD(delayed_list);
 
-static void sig_handler(int signum)
-{
-	pid_t pid;
 
-	dbg("caught signal %d", signum);
-	switch (signum) {
-	case SIGALRM:
-		dbg("event timeout reached");
-		break;
-	case SIGCHLD:
-		/* catch signals from exiting childs */
-		while ( (pid = waitpid(-1, NULL, WNOHANG)) > 0) {
-			dbg("exec finished, pid %d", pid);
-			running_remove_queue(pid);
-		}
-		break;
-	case SIGINT:
-	case SIGTERM:
-		if (lock_file >= 0) {
-			close(lock_file);
-			unlink(lock_filename);
-		}
-		exit(20 + signum);
-		break;
-	default:
-		dbg("unhandled signal");
-	}
-}
-
-static void set_timeout(int seconds)
+static void msg_dump_queue(void)
 {
-	alarm(seconds);
-	dbg("set timeout in %d seconds", seconds);
-}
+	struct hotplug_msg *msg;
 
-static int running_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move sequence %d [%d] to running queue '%s'",
-	    msg->seqnum, msg->pid, msg->devpath);
-	list_move_tail(&msg->list, &running_list);
-	return 0;
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static int running_remove_queue(pid_t  pid)
+static void msg_dump(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
-
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (child->pid == pid) {
-			list_del_init(&child->list);
-			free(child);
-			return 0;
-		}
-	return -EINVAL;
+	dbg("sequence %d, '%s', '%s', '%s'",
+	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static pid_t running_getpid_by_devpath(struct hotplug_msg *msg)
+/* allocates a new message */
+static struct hotplug_msg *msg_create(void)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
+	struct hotplug_msg *new_msg;
 
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (strncmp(child->devpath, msg->devpath, sizeof(child->devpath)) == 0)
-			return child->pid;
-	return 0;
+	new_msg = malloc(sizeof(struct hotplug_msg));
+	if (new_msg == NULL) {
+		dbg("error malloc");
+		return NULL;
+	}
+	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
+	return new_msg;
 }
 
-static void delayed_dump_queue(void)
+/* orders the message in the queue by sequence number */
+static void msg_queue_insert(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
+	struct hotplug_msg *loop_msg;
 
-	list_for_each_entry(child, &delayed_list, list)
-		dbg("event for '%s' in queue", child->devpath);
-}
+	dbg("add message seq %d", msg->seqnum);
 
-static int delayed_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move event to delayed queue '%s'", msg->devpath);
-	list_move_tail(&msg->list, &delayed_list);
-	return 0;
-}
+	/* sort message by sequence number into list*/
+	list_for_each_entry(loop_msg, &msg_list, list)
+		if (loop_msg->seqnum > msg->seqnum)
+			break;
+	list_add_tail(&msg->list, &loop_msg->list);
 
-static void delayed_check_queue(void)
-{
-	struct hotplug_msg *delayed_child;
-	struct hotplug_msg *running_child;
-	struct hotplug_msg *tmp_child;
-
-	/* see if we have delayed exec's that can run now */
-	list_for_each_entry_safe(delayed_child, tmp_child, &delayed_list, list)
-		list_for_each_entry_safe(running_child, tmp_child, &running_list, list)
-			if (strncmp(delayed_child->devpath, running_child->devpath,
-			    sizeof(running_child->devpath)) == 0) {
-				dbg("delayed exec for '%s' can run now", delayed_child->devpath);
-				msg_exec(delayed_child);
-			}
-}
+	/* store timestamp of queuing */
+	msg->queue_time = time(NULL);
 
-static void msg_dump(struct hotplug_msg *msg)
-{
-	dbg("sequence %d, '%s', '%s', '%s'",
-	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&msg_active_lock);
+	pthread_cond_signal(&msg_active);
+	pthread_mutex_unlock(&msg_active_lock);
+
+	return ;
 }
 
-static int msg_exec(struct hotplug_msg *msg)
+/* forks event and removes event from run queue when finished */
+static void *run_threads(void * parm)
 {
 	pid_t pid;
+	struct hotplug_msg *msg;
 
-	msg_dump(msg);
-
+	msg = parm;
 	setenv("ACTION", msg->action, 1);
 	setenv("DEVPATH", msg->devpath, 1);
 
-	/* delay exec, if we already have a udev working on the same devpath */
-	pid = running_getpid_by_devpath(msg);
-	if (pid != 0) {
-		dbg("delay exec of sequence %d, [%d] already working on '%s'",
-		    msg->seqnum, pid, msg->devpath);
-		delayed_moveto_queue(msg);
-	}
-
 	pid = fork();
 	switch (pid) {
 	case 0:
@@ -188,128 +134,191 @@
 		break;
 	case -1:
 		dbg("fork of child failed");
-		return -1;
+		goto exit;
 	default:
-		/* exec in background, get the SIGCHLD with the sig handler */
-		msg->pid = pid;
-		running_moveto_queue(msg);
-		break;
+		/* wait for exit of child */
+		dbg("==> exec seq %d [%d] working at '%s'",
+		    msg->seqnum, pid, msg->devpath);
+		wait(NULL);
+		dbg("<== exec seq %d came back", msg->seqnum);
 	}
-	return 0;
+
+exit:
+	/* remove event from run list */
+	pthread_mutex_lock(&running_lock);
+	list_del_init(&msg->list);
+	pthread_mutex_unlock(&running_lock);
+
+	free(msg);
+
+	/* signal queue activity to exec manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+
+	pthread_exit(0);
 }
 
-static void msg_dump_queue(void)
+/* returns already running task with devpath */
+static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
 
-	list_for_each_entry(msg, &msg_list, list)
-		dbg("sequence %d in queue", msg->seqnum);
+	list_for_each_entry_safe(loop_msg, tmp_msg, &running_list, list)
+		if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
+			return loop_msg;
+	return NULL;
 }
 
-static void msg_check_queue(void)
+/* queue management executes the events and delays events for the same devpath */
+static void *exec_queue_manager(void * parm)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
 	struct hotplug_msg *tmp_msg;
-	time_t msg_age;
+	struct hotplug_msg *msg;
+	pthread_t run_tid;
 
-recheck:
-	/* dispatch events until one is missing */
-	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
-		if (msg->seqnum != expect_seqnum)
-			break;
-		msg_exec(msg);
-		expect_seqnum++;
-	}
+	while (1) {
+		dbg("exec list manager");
+		pthread_mutex_lock(&exec_lock);
 
-	/* recalculate next timeout */
-	if (list_empty(&msg_list) == 0) {
-		msg_age = time(NULL) - msg->queue_time;
-		if (msg_age > EVENT_TIMEOUT_SEC-1) {
-			info("event %d, age %li seconds, skip event %d-%d",
-			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
-			expect_seqnum = msg->seqnum;
-			goto recheck;
+		list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, list) {
+			msg = running_with_devpath(loop_msg);
+			if (msg == NULL) {
+				/* move event to run list */
+				pthread_mutex_lock(&running_lock);
+				list_move_tail(&loop_msg->list, &running_list);
+				pthread_mutex_unlock(&running_lock);
+
+				pthread_create(&run_tid, NULL, run_threads, (void *) loop_msg);
+				pthread_detach(run_tid);
+
+				dbg("moved seq %d to running list", loop_msg->seqnum);
+			} else {
+				dbg("delay seq %d, cause seq %d already working on '%s'",
+				    loop_msg->seqnum, msg->seqnum, msg->devpath);
+			}
 		}
 
-		/* the first sequence gets its own timeout */
-		if (expect_seqnum == 0) {
-			msg_age = EVENT_TIMEOUT_SEC - FIRST_EVENT_TIMEOUT_SEC;
-			expect_seqnum = 1;
-		}
+		pthread_mutex_unlock(&exec_lock);
 
-		set_timeout(EVENT_TIMEOUT_SEC - msg_age);
-		return;
+		/* wait for activation, new events or childs coming back */
+		pthread_mutex_lock(&exec_active_lock);
+		pthread_cond_wait(&exec_active, &exec_active_lock);
+		pthread_mutex_unlock(&exec_active_lock);
 	}
 }
 
-static int msg_add_queue(struct hotplug_msg *msg)
+/* move message from incoming to exec queue */
+static void msg_move_exec(struct list_head *head)
 {
-	struct hotplug_msg *new_msg;
+	list_move_tail(head, &exec_list);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+}
+
+/* queue management thread handles the timeouts and dispatches the events */
+static void *msg_queue_manager(void * parm)
+{
+	struct hotplug_msg *loop_msg;
 	struct hotplug_msg *tmp_msg;
+	time_t msg_age = 0;
+	struct timespec tv;
 
-	new_msg = malloc(sizeof(*new_msg));
-	if (new_msg == NULL) {
-		dbg("error malloc");
-		return -ENOMEM;
-	}
-	memcpy(new_msg, msg, sizeof(*new_msg));
+	while (1) {
+		dbg("msg queue manager, next expected is %d", expected_seqnum);
+		pthread_mutex_lock(&msg_lock);
+		pthread_mutex_lock(&exec_lock);
 
-	/* store timestamp of queuing */
-	new_msg->queue_time = time(NULL);
+recheck:
+		list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, list) {
+			/* move event with expected sequence to the exec list */
+			if (loop_msg->seqnum == expected_seqnum) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum++;
+				dbg("moved seq %d to exec, next expected is %d",
+				    loop_msg->seqnum, expected_seqnum);
+				continue;
+			}
 
-	/* sort message by sequence number into list*/
-	list_for_each_entry(tmp_msg, &msg_list, list)
-		if (tmp_msg->seqnum > new_msg->seqnum)
-			break;
-	list_add_tail(&new_msg->list, &tmp_msg->list);
+			/* move event with expired timeout to the exec list */
+			msg_age = time(NULL) - loop_msg->queue_time;
+			if (msg_age > EVENT_TIMEOUT_SEC-1) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum = loop_msg->seqnum+1;
+				dbg("moved seq %d to exec, reset next expected to %d",
+				    loop_msg->seqnum, expected_seqnum);
+				goto recheck;
+			} else {
+				break;
+			}
+		}
 
-	return 0;
+		msg_dump_queue();
+		pthread_mutex_unlock(&exec_lock);
+		pthread_mutex_unlock(&msg_lock);
+
+		/* wait until queue gets active or next message timeout expires */
+		pthread_mutex_lock(&msg_active_lock);
+
+		if (list_empty(&msg_list) == 0) {
+			tv.tv_sec = time(NULL) + EVENT_TIMEOUT_SEC - msg_age;
+			tv.tv_nsec = 0;
+			dbg("next event expires in %li seconds",
+			    EVENT_TIMEOUT_SEC - msg_age);
+			pthread_cond_timedwait(&msg_active, &msg_active_lock, &tv);
+		} else {
+			pthread_cond_wait(&msg_active, &msg_active_lock);
+		}
+
+		pthread_mutex_unlock(&msg_active_lock);
+	}
 }
 
-static void work(void)
+/* every connect creates a thread which gets the msg, queues it and exits */
+static void *client_threads(void * parm)
 {
+	int sock;
 	struct hotplug_msg *msg;
-	int msgid;
-	key_t key;
-	char buf[BUFFER_SIZE];
-	int ret;
-
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	msg = (struct hotplug_msg *) buf;
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("open message queue error");
-		exit(1);
+	int retval;
+
+	sock = (int) parm;
+
+	msg = msg_create();
+	if (msg == NULL) {
+		dbg("unable to store message");
+		goto exit;
 	}
-	while (1) {
-		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
-		if (ret != -1) {
-			dbg("received sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
-			if (msg->seqnum >= expect_seqnum) {
-				msg_add_queue(msg);
-				msg_dump_queue();
-				msg_check_queue();
-				continue;
-			}
-			dbg("too late for event with sequence %d, event skipped ", msg->seqnum);
-		} else {
-			if (errno == EINTR) {
-				msg_check_queue();
-				msg_dump_queue();
-				delayed_check_queue();
-				delayed_dump_queue();
-				continue;
-			}
-			dbg("ipc message receive error '%s'", strerror(errno));
-		}
+
+	retval = recv(sock, msg, sizeof(struct hotplug_msg), 0);
+	if (retval <  0) {
+		dbg("unable to receive message");
+		goto exit;
+	}
+
+	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
+		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		goto exit;
 	}
+
+	pthread_mutex_lock(&msg_lock);
+	msg_queue_insert(msg);
+	pthread_mutex_unlock(&msg_lock);
+
+exit:
+	close(sock);
+	pthread_exit(0);
 }
 
 static int one_and_only(void)
 {
-	char string[100];
+	char string[50];
+	int lock_file;
 
-	lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
+	lock_file = open(UDEVD_LOCK, O_RDWR | O_CREAT, 0x640);
 
 	/* see if we can open */
 	if (lock_file < 0)
@@ -317,6 +326,7 @@
 	
 	/* see if we can lock */
 	if (lockf(lock_file, F_TLOCK, 0) < 0) {
+		dbg("unable to lock file, udevd already running");
 		close(lock_file);
 		return -1;
 	}
@@ -329,16 +339,69 @@
 
 int main(int argc, char *argv[])
 {
+	pthread_t cli_tid;
+	pthread_t mgr_msg_tid;
+	pthread_t mgr_exec_tid;
+	int ssock;
+	int csock;
+	struct sockaddr_un saddr;
+	struct sockaddr_un caddr;
+	socklen_t clen;
+	int retval;
+
 	/* only let one version of the daemon run at any one time */
 	if (one_and_only() != 0)
 		exit(0);
 
-	/* set up signal handler */
-	signal(SIGINT, sig_handler);
-	signal(SIGTERM, sig_handler);
-	signal(SIGALRM, sig_handler);
-	signal(SIGCHLD, sig_handler);
+	unlink(UDEVD_SOCKET);
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, UDEVD_SOCKET);
+
+	ssock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (ssock == -1) {
+		dbg("error getting socket");
+		exit(1);
+	}
+
+	retval = bind(ssock, &saddr, sizeof(saddr));
+	if (retval < 0) {
+		dbg("bind failed\n");
+		goto exit;
+	}
+
+	retval = listen(ssock, SOMAXCONN);
+	if (retval < 0) {
+		dbg("listen failed\n");
+		goto exit;
+	}
+
+	pthread_mutex_init(&msg_lock, NULL);
+	pthread_mutex_init(&msg_active_lock, NULL);
+	pthread_mutex_init(&exec_lock, NULL);
+	pthread_mutex_init(&exec_active_lock, NULL);
+	pthread_mutex_init(&running_lock, NULL);
+
+	/* init queue management */
+	pthread_create(&mgr_msg_tid, NULL, msg_queue_manager, NULL);
+	pthread_detach(mgr_msg_tid);
+	pthread_create(&mgr_exec_tid, NULL, exec_queue_manager, NULL);
+	pthread_detach(mgr_exec_tid);
 
-	work();
+	clen = sizeof(caddr);
+	/* main loop */
+	while (1) {
+		csock = accept(ssock, &caddr, &clen);
+		if (csock < 0) {
+			if (errno == EINTR)
+				continue;
+			dbg("client accept failed\n");
+		}
+
+		pthread_create(&cli_tid, NULL, client_threads, (void *) csock);
+		pthread_detach(cli_tid);
+	}
+exit:
+	close(ssock);
 	exit(0);
 }
===== udevd.h 1.4 vs edited =====
--- 1.4/udevd.h	Tue Jan 27 08:29:28 2004
+++ edited/udevd.h	Thu Jan 29 16:38:16 2004
@@ -4,6 +4,7 @@
  * Userspace devfs
  *
  * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
  *	This program is free software; you can redistribute it and/or modify it
@@ -23,16 +24,14 @@
 
 #include "list.h"
 
-#define FIRST_EVENT_TIMEOUT_SEC		1
+#define UDEV_MAGIC			"udev_" UDEV_VERSION
 #define EVENT_TIMEOUT_SEC		5
-#define UDEVSEND_RETRY_COUNT		50 /* x 10 millisec */
-
-#define IPC_KEY_ID			1
-#define HOTPLUGMSGTYPE			44
-
+#define UDEVD_START_TIMEOUT		20 /* x 100 millisec */
+#define UDEVD_SOCKET			"/tmp/udevd.socket"
+#define UDEVD_LOCK			"/var/run/udevd.pid"
 
 struct hotplug_msg {
-	long mtype;
+	char magic[20];
 	struct list_head list;
 	pid_t pid;
 	int seqnum;
===== udevsend.c 1.8 vs edited =====
--- 1.8/udevsend.c	Tue Jan 27 08:29:28 2004
+++ edited/udevsend.c	Thu Jan 29 13:06:09 2004
@@ -32,12 +32,15 @@
 #include <unistd.h>
 #include <time.h>
 #include <wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #include "udev.h"
 #include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
+
 static inline char *get_action(void)
 {
 	char *action;
@@ -66,7 +69,7 @@
 			    char *devpath, char *subsystem, int seqnum)
 {
 	memset(msg, 0x00, sizeof(*msg));
-	msg->mtype = HOTPLUGMSGTYPE;
+	strfieldcpy(msg->magic, UDEV_MAGIC);
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
 	strncpy(msg->devpath, devpath, 128);
@@ -108,12 +111,8 @@
 	return 0;
 }
 
-
 int main(int argc, char* argv[])
 {
-	int msgid;
-	key_t key;
-	struct msqid_ds msg_queue;
 	struct hotplug_msg message;
 	char *action;
 	char *devpath;
@@ -124,6 +123,8 @@
 	int size;
 	int loop;
 	struct timespec tspec;
+	int sock;
+	struct sockaddr_un saddr;
 
 	subsystem = argv[1];
 	if (subsystem == NULL) {
@@ -150,41 +151,57 @@
 	}
 	seq = atoi(seqnum);
 
-	/* create ipc message queue or get id of our existing one */
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	dbg("using ipc queue 0x%0x", key);
-	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("error open ipc queue");
+	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (sock == -1) {
+		dbg("error getting socket");
 		goto exit;
 	}
 
-	/* send ipc message to the daemon */
-	retval = msgsnd(msgid, &message, size, 0);
-	if (retval == -1) {
-		dbg("error sending ipc message");
-		goto exit;
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, UDEVD_SOCKET);
+
+	/* try to connect, if it fails start daemon */
+	retval = connect(sock, &saddr, sizeof(saddr));
+	if (retval != -1) {
+		goto send;
+	} else {
+		dbg("connect failed, try starting daemon...");
+		retval = start_daemon();
+		if (retval == 0) {
+			dbg("daemon started");
+		} else {
+			dbg("error starting daemon");
+			goto exit;
+		}
 	}
 
-	/* get state of ipc queue */
+	/* try to connect while daemon to starts */
 	tspec.tv_sec = 0;
-	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = UDEVSEND_RETRY_COUNT;
+	tspec.tv_nsec = 100000000;  /* 100 millisec */
+	loop = UDEVD_START_TIMEOUT;
 	while (loop--) {
-		retval = msgctl(msgid, IPC_STAT, &msg_queue);
-		if (retval == -1) {
-			dbg("error getting info on ipc queue");
-			goto exit;
-		}
-		if (msg_queue.msg_qnum == 0)
-			goto exit;
+		retval = connect(sock, &saddr, sizeof(saddr));
+		if (retval != -1)
+			goto send;
+		else
+			dbg("retry to connect %d", UDEVD_START_TIMEOUT - loop);
 		nanosleep(&tspec, NULL);
 	}
+	dbg("error connecting to daemon, start daemon failed");
+	goto exit;
 
-	info("message is still in the ipc queue, starting daemon...");
-	retval = start_daemon();
+send:
+	size = build_hotplugmsg(&message, action, devpath, subsystem, seq);
+	retval = send(sock, &message, size, 0);
+	if (retval == -1) {
+		dbg("error sending message");
+		close (sock);
+		goto exit;
+	}
+	close (sock);
+	return 0;
 
 exit:
-	return retval;
+	return 1;
 }
===== test/udevd_test.sh 1.4 vs edited =====
--- 1.4/test/udevd_test.sh	Tue Jan 27 08:29:28 2004
+++ edited/test/udevd_test.sh	Wed Jan 28 22:23:22 2004
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # kill daemon, first event will start it again
-killall udevd
+#killall udevd
 
 # 3 x connect/disconnect sequence of sda/sdb/sdc
 

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (13 preceding siblings ...)
  2004-01-29 15:55 ` Kay Sievers
@ 2004-01-31  2:42 ` Kay Sievers
  2004-02-01  9:08 ` Greg KH
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-01-31  2:42 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 4657 bytes --]

On Thu, Jan 29, 2004 at 04:55:11PM +0100, Kay Sievers wrote:
> On Thu, Jan 29, 2004 at 02:56:25AM +0100, Kay Sievers wrote:
> > On Wed, Jan 28, 2004 at 10:47:36PM +0100, Kay Sievers wrote:
> > > On Tue, Jan 27, 2004 at 11:13:09AM -0800, Greg KH wrote:
> > > > On Tue, Jan 27, 2004 at 08:08:09PM +0100, Kay Sievers wrote:
> > > > > On Tue, Jan 27, 2004 at 07:56:04AM +0100, Kay Sievers wrote:
> > > > > > On Mon, Jan 26, 2004 at 11:28:19AM -0800, Greg KH wrote:
> > > > > > > On Mon, Jan 26, 2004 at 08:11:10PM +0100, Kay Sievers wrote:
> > > > > > > > On Mon, Jan 26, 2004 at 10:22:34AM -0800, Greg KH wrote:
> > > > > > > > > On Sun, Jan 25, 2004 at 09:03:14PM +0100, Kay Sievers wrote:
> > > > > > > > > >   1. We are much too slow.
> > > > > > > > > >      We want to exec the  real udev in the background, but a 'remove'
> > > > > > > > > >      is much much faster than a 'add', so we have a problem.
> > > > > > > > > >      Question: is it neccessary to order events for different devpath's?
> > > > > > > > > >      If no, we may wait_pid() for the exec only if we have another udev
> > > > > > > > > >      working on the same devpath.
> > > > > > > > > 
> > > > > > > > > But how will we keep track of that?  It's probably easier just to wait
> > > > > > > > > for each one to finish, right?
> > > > > > > > 
> > > > > > > > We leave the message in the queue until we reach the SIGCHLD for this
> > > > > > > > pid. So we can search the queue if we are already working on this devpath,
> > > > > > > > and delay the new exec until the former exec comes back.
> > > > > > > 
> > > > > > > Ok, if that isn't too much trouble.
> > > > > > > 
> > > > > > > > Is it feasible to run in parallel for different paths, or can you think
> > > > > > > > of any problem?
> > > > > > > 
> > > > > > > I can't think of any problem with that.
> > > > > > 
> > > > > > Here is the next round. We have three queues now. All incoming messages
> > > > > > are queued in msg_list and if nothing is missing we move it to the
> > > > > > running_list and exec in the background.
> > > > > > If the exec comes back, it removes the message from the running_list and
> > > > > > frees the message.
> > > > > > 
> > > > > > Before we exec, we check the running_list if there is a udev running on
> > > > > > the same device path. If yes, we move the message to the delay_list. If
> > > > > > the former exec comes back, we move the message to the running_list and
> > > > > > exec it.
> > > > > 
> > > > > Oh, sorry forget about it now.
> > > > > I will come up with something better tested.
> > > > 
> > > > Oops, I just applied this version :)
> > > > 
> > > > I'll try testing this later on today.
> > > 
> > > Oh, couldn't resist to try threads.
> > > It's a multithreaded udevd that communicates through a localhost socket.
> > > The message includes a magic with the udev version, so we don't accept
> > > older udevsend's.
> > > 
> > > No need for locking, cause we can't bind two sockets on the same address.
> > > The daemon tries to connect and if it fails it starts the daemon.
> > > 
> > > We create a thread for every incoming connection, handle over the socket,
> > > sort the messages in the global message queue and exit the thread.
> > > Huh, that was easy with threads :)
> > > 
> > > With the addition of a message we wakeup the queue manager thread and
> > > handle timeouts or move the message to the global exec list. This wakes
> > > up the exec list manager who looks if a process is already running for this
> > > device path.
> > > If yes, the exec is delayed otherwise we create a thread that execs udev.
> > > n the background. With the return of udev we free the message and wakeup
> > > the exec list manager to look if something is pending.
> > > 
> > > It is just a quick shot, cause I couldn't solve the problems with fork an
> > > scheduling and I wanted to see if I'm to stupid  :)
> > > But if anybody with a better idea or more experience with I/O scheduling
> > > we may go another way. The remaining problem is that klibc doesn't support
> > > threads.
> > > 
> > > By now, we don't exec anything, it's just a sleep 3 for every exec,
> > > but you can see the queue management by watching syslog and do:
> > > 
> > >   DEVPATH=/abc ACTION=add SEQNUM=0 ./udevsend /abc
> 
> Next version, switched to unix domain sockets.

Next cleaned up version. Hey, nobody wants to try it :)

Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader
every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3
devices plugged in every second and don't run into any problem but a _very_
big udevd queue.

thanks,
Kay


[-- Attachment #2: 01-udevd-threads.patch --]
[-- Type: text/plain, Size: 21199 bytes --]

===== Makefile 1.93 vs edited =====
--- 1.93/Makefile	Tue Jan 27 08:29:28 2004
+++ edited/Makefile	Thu Jan 29 16:46:29 2004
@@ -255,7 +255,7 @@
 	$(STRIPCMD) $@
 
 $(DAEMON): udevd.h udevd.o udevd.o logging.o
-	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
+	$(LD) $(LDFLAGS) -lpthread -o $@ $(CRT0) udevd.o logging.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $@
 
 $(SENDER): udevd.h udevsend.o udevd.o logging.o
===== udevd.c 1.7 vs edited =====
--- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
+++ edited/udevd.c	Sat Jan 31 03:08:44 2004
@@ -1,9 +1,6 @@
 /*
- * udevd.c
+ * udevd.c - hotplug event serializer
  *
- * Userspace devfs
- *
- * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
@@ -24,9 +21,7 @@
 
 #include <stddef.h>
 #include <sys/types.h>
-#include <sys/ipc.h>
 #include <sys/wait.h>
-#include <sys/msg.h>
 #include <signal.h>
 #include <unistd.h>
 #include <errno.h>
@@ -35,6 +30,10 @@
 #include <string.h>
 #include <time.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
 
 #include "list.h"
 #include "udev.h"
@@ -43,141 +42,82 @@
 #include "logging.h"
 
 
-#define BUFFER_SIZE			1024
-
-static int running_remove_queue(pid_t pid);
-static int msg_exec(struct hotplug_msg *msg);
-
-static int expect_seqnum = 0;
-static int lock_file = -1;
-static char *lock_filename = ".udevd_lock";
+static pthread_mutex_t  msg_lock;
+static pthread_mutex_t  msg_active_lock;
+static pthread_cond_t msg_active;
+static pthread_mutex_t  exec_lock;
+static pthread_mutex_t  exec_active_lock;
+static pthread_cond_t exec_active;
+static pthread_mutex_t  running_lock;
+static pthread_attr_t thr_attr;
+static int expected_seqnum = 0;
 
 LIST_HEAD(msg_list);
+LIST_HEAD(exec_list);
 LIST_HEAD(running_list);
-LIST_HEAD(delayed_list);
-
-static void sig_handler(int signum)
-{
-	pid_t pid;
 
-	dbg("caught signal %d", signum);
-	switch (signum) {
-	case SIGALRM:
-		dbg("event timeout reached");
-		break;
-	case SIGCHLD:
-		/* catch signals from exiting childs */
-		while ( (pid = waitpid(-1, NULL, WNOHANG)) > 0) {
-			dbg("exec finished, pid %d", pid);
-			running_remove_queue(pid);
-		}
-		break;
-	case SIGINT:
-	case SIGTERM:
-		if (lock_file >= 0) {
-			close(lock_file);
-			unlink(lock_filename);
-		}
-		exit(20 + signum);
-		break;
-	default:
-		dbg("unhandled signal");
-	}
-}
 
-static void set_timeout(int seconds)
+static void msg_dump_queue(void)
 {
-	alarm(seconds);
-	dbg("set timeout in %d seconds", seconds);
-}
+	struct hotplug_msg *msg;
 
-static int running_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move sequence %d [%d] to running queue '%s'",
-	    msg->seqnum, msg->pid, msg->devpath);
-	list_move_tail(&msg->list, &running_list);
-	return 0;
+	list_for_each_entry(msg, &msg_list, list)
+		dbg("sequence %d in queue", msg->seqnum);
 }
 
-static int running_remove_queue(pid_t  pid)
+static void msg_dump(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
-
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (child->pid == pid) {
-			list_del_init(&child->list);
-			free(child);
-			return 0;
-		}
-	return -EINVAL;
+	dbg("sequence %d, '%s', '%s', '%s'",
+	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-static pid_t running_getpid_by_devpath(struct hotplug_msg *msg)
+/* allocates a new message */
+static struct hotplug_msg *msg_create(void)
 {
-	struct hotplug_msg *child;
-	struct hotplug_msg *tmp_child;
+	struct hotplug_msg *new_msg;
 
-	list_for_each_entry_safe(child, tmp_child, &running_list, list)
-		if (strncmp(child->devpath, msg->devpath, sizeof(child->devpath)) == 0)
-			return child->pid;
-	return 0;
+	new_msg = malloc(sizeof(struct hotplug_msg));
+	if (new_msg == NULL) {
+		dbg("error malloc");
+		return NULL;
+	}
+	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
+	return new_msg;
 }
 
-static void delayed_dump_queue(void)
+/* orders the message in the queue by sequence number */
+static void msg_queue_insert(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *child;
+	struct hotplug_msg *loop_msg;
 
-	list_for_each_entry(child, &delayed_list, list)
-		dbg("event for '%s' in queue", child->devpath);
-}
+	/* sort message by sequence number into list*/
+	list_for_each_entry(loop_msg, &msg_list, list)
+		if (loop_msg->seqnum > msg->seqnum)
+			break;
+	list_add_tail(&msg->list, &loop_msg->list);
+	dbg("queued message seq %d", msg->seqnum);
 
-static int delayed_moveto_queue(struct hotplug_msg *msg)
-{
-	dbg("move event to delayed queue '%s'", msg->devpath);
-	list_move_tail(&msg->list, &delayed_list);
-	return 0;
-}
+	/* store timestamp of queuing */
+	msg->queue_time = time(NULL);
 
-static void delayed_check_queue(void)
-{
-	struct hotplug_msg *delayed_child;
-	struct hotplug_msg *running_child;
-	struct hotplug_msg *tmp_child;
-
-	/* see if we have delayed exec's that can run now */
-	list_for_each_entry_safe(delayed_child, tmp_child, &delayed_list, list)
-		list_for_each_entry_safe(running_child, tmp_child, &running_list, list)
-			if (strncmp(delayed_child->devpath, running_child->devpath,
-			    sizeof(running_child->devpath)) == 0) {
-				dbg("delayed exec for '%s' can run now", delayed_child->devpath);
-				msg_exec(delayed_child);
-			}
-}
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&msg_active_lock);
+	pthread_cond_signal(&msg_active);
+	pthread_mutex_unlock(&msg_active_lock);
 
-static void msg_dump(struct hotplug_msg *msg)
-{
-	dbg("sequence %d, '%s', '%s', '%s'",
-	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
+	return ;
 }
 
-static int msg_exec(struct hotplug_msg *msg)
+/* forks event and removes event from run queue when finished */
+static void *run_threads(void * parm)
 {
 	pid_t pid;
+	struct hotplug_msg *msg;
 
-	msg_dump(msg);
-
+	msg = parm;
 	setenv("ACTION", msg->action, 1);
 	setenv("DEVPATH", msg->devpath, 1);
 
-	/* delay exec, if we already have a udev working on the same devpath */
-	pid = running_getpid_by_devpath(msg);
-	if (pid != 0) {
-		dbg("delay exec of sequence %d, [%d] already working on '%s'",
-		    msg->seqnum, pid, msg->devpath);
-		delayed_moveto_queue(msg);
-	}
-
 	pid = fork();
 	switch (pid) {
 	case 0:
@@ -188,135 +128,206 @@
 		break;
 	case -1:
 		dbg("fork of child failed");
-		return -1;
+		goto exit;
 	default:
-		/* exec in background, get the SIGCHLD with the sig handler */
-		msg->pid = pid;
-		running_moveto_queue(msg);
-		break;
+		/* wait for exit of child */
+		dbg("==> exec seq %d [%d] working at '%s'",
+		    msg->seqnum, pid, msg->devpath);
+		wait(NULL);
+		dbg("<== exec seq %d came back", msg->seqnum);
 	}
-	return 0;
+
+exit:
+	/* remove event from run list */
+	pthread_mutex_lock(&running_lock);
+	list_del_init(&msg->list);
+	pthread_mutex_unlock(&running_lock);
+
+	free(msg);
+
+	/* signal queue activity to exec manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+
+	pthread_exit(0);
 }
 
-static void msg_dump_queue(void)
+/* returns already running task with devpath */
+static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
 {
-	struct hotplug_msg *msg;
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
 
-	list_for_each_entry(msg, &msg_list, list)
-		dbg("sequence %d in queue", msg->seqnum);
+	list_for_each_entry_safe(loop_msg, tmp_msg, &running_list, list)
+		if (strncmp(loop_msg->devpath, msg->devpath, sizeof(loop_msg->devpath)) == 0)
+			return loop_msg;
+	return NULL;
 }
 
-static void msg_check_queue(void)
+/* queue management executes the events and delays events for the same devpath */
+static void *exec_queue_manager(void * parm)
 {
+	struct hotplug_msg *loop_msg;
+	struct hotplug_msg *tmp_msg;
 	struct hotplug_msg *msg;
+	pthread_t run_tid;
+
+	while (1) {
+		pthread_mutex_lock(&exec_lock);
+		list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, list) {
+			msg = running_with_devpath(loop_msg);
+			if (msg == NULL) {
+				/* move event to run list */
+				pthread_mutex_lock(&running_lock);
+				list_move_tail(&loop_msg->list, &running_list);
+				pthread_mutex_unlock(&running_lock);
+
+				pthread_create(&run_tid, &thr_attr, run_threads, (void *) loop_msg);
+
+				dbg("moved seq %d to running list", loop_msg->seqnum);
+			} else {
+				dbg("delay seq %d, cause seq %d already working on '%s'",
+				    loop_msg->seqnum, msg->seqnum, msg->devpath);
+			}
+		}
+		pthread_mutex_unlock(&exec_lock);
+
+		/* wait for activation, new events or childs coming back */
+		pthread_mutex_lock(&exec_active_lock);
+		pthread_cond_wait(&exec_active, &exec_active_lock);
+		pthread_mutex_unlock(&exec_active_lock);
+	}
+}
+
+/* move message from incoming to exec queue */
+static void msg_move_exec(struct list_head *head)
+{
+	list_move_tail(head, &exec_list);
+	/* signal queue activity to manager */
+	pthread_mutex_lock(&exec_active_lock);
+	pthread_cond_signal(&exec_active);
+	pthread_mutex_unlock(&exec_active_lock);
+}
+
+/* queue management thread handles the timeouts and dispatches the events */
+static void *msg_queue_manager(void * parm)
+{
+	struct hotplug_msg *loop_msg;
 	struct hotplug_msg *tmp_msg;
-	time_t msg_age;
+	time_t msg_age = 0;
+	struct timespec tv;
 
+	while (1) {
+		dbg("msg queue manager, next expected is %d", expected_seqnum);
+		pthread_mutex_lock(&msg_lock);
+		pthread_mutex_lock(&exec_lock);
 recheck:
-	/* dispatch events until one is missing */
-	list_for_each_entry_safe(msg, tmp_msg, &msg_list, list) {
-		if (msg->seqnum != expect_seqnum)
-			break;
-		msg_exec(msg);
-		expect_seqnum++;
-	}
+		list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, list) {
+			/* move event with expected sequence to the exec list */
+			if (loop_msg->seqnum == expected_seqnum) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum++;
+				dbg("moved seq %d to exec, next expected is %d",
+				    loop_msg->seqnum, expected_seqnum);
+				continue;
+			}
 
-	/* recalculate next timeout */
-	if (list_empty(&msg_list) == 0) {
-		msg_age = time(NULL) - msg->queue_time;
-		if (msg_age > EVENT_TIMEOUT_SEC-1) {
-			info("event %d, age %li seconds, skip event %d-%d",
-			     msg->seqnum, msg_age, expect_seqnum, msg->seqnum-1);
-			expect_seqnum = msg->seqnum;
-			goto recheck;
+			/* move event with expired timeout to the exec list */
+			msg_age = time(NULL) - loop_msg->queue_time;
+			if (msg_age > EVENT_TIMEOUT_SEC-1) {
+				msg_move_exec(&loop_msg->list);
+				expected_seqnum = loop_msg->seqnum+1;
+				dbg("moved seq %d to exec, reset next expected to %d",
+				    loop_msg->seqnum, expected_seqnum);
+				goto recheck;
+			} else {
+				break;
+			}
 		}
 
-		/* the first sequence gets its own timeout */
-		if (expect_seqnum == 0) {
-			msg_age = EVENT_TIMEOUT_SEC - FIRST_EVENT_TIMEOUT_SEC;
-			expect_seqnum = 1;
+		msg_dump_queue();
+		pthread_mutex_unlock(&exec_lock);
+		pthread_mutex_unlock(&msg_lock);
+
+		/* wait until queue gets active or next message timeout expires */
+		pthread_mutex_lock(&msg_active_lock);
+
+		if (list_empty(&msg_list) == 0) {
+			tv.tv_sec = time(NULL) + EVENT_TIMEOUT_SEC - msg_age;
+			tv.tv_nsec = 0;
+			dbg("next event expires in %li seconds",
+			    EVENT_TIMEOUT_SEC - msg_age);
+			pthread_cond_timedwait(&msg_active, &msg_active_lock, &tv);
+		} else {
+			pthread_cond_wait(&msg_active, &msg_active_lock);
 		}
-
-		set_timeout(EVENT_TIMEOUT_SEC - msg_age);
-		return;
+		pthread_mutex_unlock(&msg_active_lock);
 	}
 }
 
-static int msg_add_queue(struct hotplug_msg *msg)
+/* every connect creates a thread which gets the msg, queues it and exits */
+static void *client_threads(void * parm)
 {
-	struct hotplug_msg *new_msg;
-	struct hotplug_msg *tmp_msg;
+	int sock;
+	struct hotplug_msg *msg;
+	int retval;
 
-	new_msg = malloc(sizeof(*new_msg));
-	if (new_msg == NULL) {
-		dbg("error malloc");
-		return -ENOMEM;
+	sock = (int) parm;
+
+	msg = msg_create();
+	if (msg == NULL) {
+		dbg("unable to store message");
+		goto exit;
 	}
-	memcpy(new_msg, msg, sizeof(*new_msg));
 
-	/* store timestamp of queuing */
-	new_msg->queue_time = time(NULL);
+	retval = recv(sock, msg, sizeof(struct hotplug_msg), 0);
+	if (retval <  0) {
+		dbg("unable to receive message");
+		goto exit;
+	}
 
-	/* sort message by sequence number into list*/
-	list_for_each_entry(tmp_msg, &msg_list, list)
-		if (tmp_msg->seqnum > new_msg->seqnum)
-			break;
-	list_add_tail(&new_msg->list, &tmp_msg->list);
+	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
+		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		goto exit;
+	}
 
-	return 0;
+	pthread_mutex_lock(&msg_lock);
+	msg_queue_insert(msg);
+	pthread_mutex_unlock(&msg_lock);
+
+exit:
+	close(sock);
+	pthread_exit(0);
 }
 
-static void work(void)
+static void sig_handler(int signum)
 {
-	struct hotplug_msg *msg;
-	int msgid;
-	key_t key;
-	char buf[BUFFER_SIZE];
-	int ret;
-
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	msg = (struct hotplug_msg *) buf;
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("open message queue error");
-		exit(1);
-	}
-	while (1) {
-		ret = msgrcv(msgid, (struct msgbuf *) buf, BUFFER_SIZE-4, HOTPLUGMSGTYPE, 0);
-		if (ret != -1) {
-			dbg("received sequence %d, expected sequence %d", msg->seqnum, expect_seqnum);
-			if (msg->seqnum >= expect_seqnum) {
-				msg_add_queue(msg);
-				msg_dump_queue();
-				msg_check_queue();
-				continue;
-			}
-			dbg("too late for event with sequence %d, event skipped ", msg->seqnum);
-		} else {
-			if (errno == EINTR) {
-				msg_check_queue();
-				msg_dump_queue();
-				delayed_check_queue();
-				delayed_dump_queue();
-				continue;
-			}
-			dbg("ipc message receive error '%s'", strerror(errno));
-		}
+	switch (signum) {
+		case SIGINT:
+		case SIGTERM:
+			unlink(UDEVD_LOCK);
+			unlink(UDEVD_SOCKET);
+			exit(20 + signum);
+			break;
+		default:
+			dbg("unhandled signal");
 	}
 }
 
 static int one_and_only(void)
 {
-	char string[100];
-
-	lock_file = open(lock_filename, O_RDWR | O_CREAT, 0x640);
+	char string[50];
+	int lock_file;
 
 	/* see if we can open */
+	lock_file = open(UDEVD_LOCK, O_RDWR | O_CREAT, 0x640);
 	if (lock_file < 0)
 		return -1;
-	
+
 	/* see if we can lock */
 	if (lockf(lock_file, F_TLOCK, 0) < 0) {
+		dbg("file is already locked, exit");
 		close(lock_file);
 		return -1;
 	}
@@ -329,16 +340,73 @@
 
 int main(int argc, char *argv[])
 {
+	int ssock;
+	int csock;
+	struct sockaddr_un saddr;
+	struct sockaddr_un caddr;
+	socklen_t clen;
+	pthread_t cli_tid;
+	pthread_t mgr_msg_tid;
+	pthread_t mgr_exec_tid;
+	int retval;
+
 	/* only let one version of the daemon run at any one time */
 	if (one_and_only() != 0)
 		exit(0);
 
-	/* set up signal handler */
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
-	signal(SIGALRM, sig_handler);
-	signal(SIGCHLD, sig_handler);
 
-	work();
-	exit(0);
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, UDEVD_SOCKET);
+
+	unlink(UDEVD_SOCKET);
+	ssock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (ssock == -1) {
+		dbg("error getting socket");
+		exit(1);
+	}
+
+	retval = bind(ssock, &saddr, sizeof(saddr));
+	if (retval < 0) {
+		dbg("bind failed\n");
+		goto exit;
+	}
+
+	retval = listen(ssock, SOMAXCONN);
+	if (retval < 0) {
+		dbg("listen failed\n");
+		goto exit;
+	}
+
+	pthread_mutex_init(&msg_lock, NULL);
+	pthread_mutex_init(&msg_active_lock, NULL);
+	pthread_mutex_init(&exec_lock, NULL);
+	pthread_mutex_init(&exec_active_lock, NULL);
+	pthread_mutex_init(&running_lock, NULL);
+
+	/* set default attributes for created threads */
+	pthread_attr_init(&thr_attr);
+	pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
+
+	/* init queue management */
+	pthread_create(&mgr_msg_tid, &thr_attr, msg_queue_manager, NULL);
+	pthread_create(&mgr_exec_tid, &thr_attr, exec_queue_manager, NULL);
+
+	clen = sizeof(caddr);
+	/* main loop */
+	while (1) {
+		csock = accept(ssock, &caddr, &clen);
+		if (csock < 0) {
+			if (errno == EINTR)
+				continue;
+			dbg("client accept failed\n");
+		}
+		pthread_create(&cli_tid, &thr_attr, client_threads, (void *) csock);
+	}
+exit:
+	close(ssock);
+	unlink(UDEVD_SOCKET);
+	exit(1);
 }
===== udevd.h 1.4 vs edited =====
--- 1.4/udevd.h	Tue Jan 27 08:29:28 2004
+++ edited/udevd.h	Sat Jan 31 03:12:52 2004
@@ -4,6 +4,7 @@
  * Userspace devfs
  *
  * Copyright (C) 2004 Ling, Xiaofeng <xiaofeng.ling@intel.com>
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *
  *	This program is free software; you can redistribute it and/or modify it
@@ -23,16 +24,21 @@
 
 #include "list.h"
 
-#define FIRST_EVENT_TIMEOUT_SEC		1
-#define EVENT_TIMEOUT_SEC		5
-#define UDEVSEND_RETRY_COUNT		50 /* x 10 millisec */
-
-#define IPC_KEY_ID			1
-#define HOTPLUGMSGTYPE			44
+/*
+ * FIXME: udev_root is post compile configurable and may also be
+ * mounted over at any time and /var/run/ and /tmp/ is unusable,
+ * cause it's cleaned at system startup, long _after_ udevd is
+ * already running. Should we use udev_init_config()?
+ */
 
+#define UDEV_MAGIC			"udev_" UDEV_VERSION
+#define EVENT_TIMEOUT_SEC		5
+#define UDEVSEND_CONNECT_RETRY		20 /* x 100 millisec */
+#define UDEVD_SOCKET			UDEV_ROOT ".udevd.socket"
+#define UDEVD_LOCK			UDEV_ROOT ".udevd.pid"
 
 struct hotplug_msg {
-	long mtype;
+	char magic[20];
 	struct list_head list;
 	pid_t pid;
 	int seqnum;
===== udevsend.c 1.8 vs edited =====
--- 1.8/udevsend.c	Tue Jan 27 08:29:28 2004
+++ edited/udevsend.c	Sat Jan 31 02:53:31 2004
@@ -32,12 +32,15 @@
 #include <unistd.h>
 #include <time.h>
 #include <wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #include "udev.h"
 #include "udev_version.h"
 #include "udevd.h"
 #include "logging.h"
 
+
 static inline char *get_action(void)
 {
 	char *action;
@@ -66,7 +69,7 @@
 			    char *devpath, char *subsystem, int seqnum)
 {
 	memset(msg, 0x00, sizeof(*msg));
-	msg->mtype = HOTPLUGMSGTYPE;
+	strfieldcpy(msg->magic, UDEV_MAGIC);
 	msg->seqnum = seqnum;
 	strncpy(msg->action, action, 8);
 	strncpy(msg->devpath, devpath, 128);
@@ -108,12 +111,8 @@
 	return 0;
 }
 
-
 int main(int argc, char* argv[])
 {
-	int msgid;
-	key_t key;
-	struct msqid_ds msg_queue;
 	struct hotplug_msg message;
 	char *action;
 	char *devpath;
@@ -124,6 +123,8 @@
 	int size;
 	int loop;
 	struct timespec tspec;
+	int sock;
+	struct sockaddr_un saddr;
 
 	subsystem = argv[1];
 	if (subsystem == NULL) {
@@ -150,41 +151,58 @@
 	}
 	seq = atoi(seqnum);
 
-	/* create ipc message queue or get id of our existing one */
-	key = ftok(UDEVD_BIN, IPC_KEY_ID);
-	dbg("using ipc queue 0x%0x", key);
-	size =  build_hotplugmsg(&message, action, devpath, subsystem, seq);
-	msgid = msgget(key, IPC_CREAT);
-	if (msgid == -1) {
-		dbg("error open ipc queue");
+	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (sock == -1) {
+		dbg("error getting socket");
 		goto exit;
 	}
 
-	/* send ipc message to the daemon */
-	retval = msgsnd(msgid, &message, size, 0);
-	if (retval == -1) {
-		dbg("error sending ipc message");
-		goto exit;
+	memset(&saddr, 0x00, sizeof(saddr));
+	saddr.sun_family = AF_LOCAL;
+	strcpy(saddr.sun_path, UDEVD_SOCKET);
+
+	/* try to connect, if it fails start daemon */
+	retval = connect(sock, &saddr, sizeof(saddr));
+	if (retval != -1) {
+		goto send;
+	} else {
+		dbg("connect failed, try starting daemon...");
+		retval = start_daemon();
+		if (retval == 0) {
+			dbg("daemon started");
+		} else {
+			dbg("error starting daemon");
+			goto exit;
+		}
 	}
 
-	/* get state of ipc queue */
+	/* try to connect while daemon to starts */
 	tspec.tv_sec = 0;
-	tspec.tv_nsec = 10000000;  /* 10 millisec */
-	loop = UDEVSEND_RETRY_COUNT;
+	tspec.tv_nsec = 100000000;  /* 100 millisec */
+	loop = UDEVSEND_CONNECT_RETRY;
 	while (loop--) {
-		retval = msgctl(msgid, IPC_STAT, &msg_queue);
-		if (retval == -1) {
-			dbg("error getting info on ipc queue");
-			goto exit;
-		}
-		if (msg_queue.msg_qnum == 0)
-			goto exit;
+		retval = connect(sock, &saddr, sizeof(saddr));
+		if (retval != -1)
+			goto send;
+		else
+			dbg("retry to connect %d",
+			    UDEVSEND_CONNECT_RETRY - loop);
 		nanosleep(&tspec, NULL);
 	}
+	dbg("error connecting to daemon, start daemon failed");
+	goto exit;
 
-	info("message is still in the ipc queue, starting daemon...");
-	retval = start_daemon();
+send:
+	size = build_hotplugmsg(&message, action, devpath, subsystem, seq);
+	retval = send(sock, &message, size, 0);
+	if (retval == -1) {
+		dbg("error sending message");
+		close (sock);
+		goto exit;
+	}
+	close (sock);
+	return 0;
 
 exit:
-	return retval;
+	return 1;
 }
===== test/udevd_test.sh 1.4 vs edited =====
--- 1.4/test/udevd_test.sh	Tue Jan 27 08:29:28 2004
+++ edited/test/udevd_test.sh	Sat Jan 31 03:30:06 2004
@@ -1,9 +1,7 @@
-#!/bin/bash
+#!/bin/sh
 
-# kill daemon, first event will start it again
-killall udevd
-
-# 3 x connect/disconnect sequence of sda/sdb/sdc
+# add/rem/add/rem/add sequence of sda/sdb/sdc
+# a few days longer and the socket of my usb-flash-reader is gone :)
 
 export SEQNUM=3
 export ACTION=add

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (14 preceding siblings ...)
  2004-01-31  2:42 ` Kay Sievers
@ 2004-02-01  9:08 ` Greg KH
  2004-02-01 18:16 ` Kay Sievers
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-02-01  9:08 UTC (permalink / raw)
  To: linux-hotplug

On Sat, Jan 31, 2004 at 03:42:20AM +0100, Kay Sievers wrote:
> 
> Next cleaned up version. Hey, nobody wants to try it :)
> 
> Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader
> every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3
> devices plugged in every second and don't run into any problem but a _very_
> big udevd queue.

Very sorry for the delay, been busy with other work these past few days.

I've applied this patch, and pushed it to the repo.  I'll try to test it
some more myself early next week, and let you know how it goes.

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (15 preceding siblings ...)
  2004-02-01  9:08 ` Greg KH
@ 2004-02-01 18:16 ` Kay Sievers
  2004-02-02  2:19 ` Kay Sievers
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-01 18:16 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 957 bytes --]

On Sun, Feb 01, 2004 at 01:08:54AM -0800, Greg KH wrote:
> On Sat, Jan 31, 2004 at 03:42:20AM +0100, Kay Sievers wrote:
> > 
> > Next cleaned up version. Hey, nobody wants to try it :)
> > 
> > Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader
> > every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3
> > devices plugged in every second and don't run into any problem but a _very_
> > big udevd queue.
> 
> Very sorry for the delay, been busy with other work these past few days.
> 
> I've applied this patch, and pushed it to the repo.  I'll try to test it
> some more myself early next week, and let you know how it goes.

Here is a small cleanup and better Makefile integration.
udevd and udevsender are now installed. Just switch HOTPLUG_EXEC from ROOT
to SENDER before install and udevsend will be called.

We may add the location of the socket and lock file to the config,
if this is needed.

thanks,
Kay

[-- Attachment #2: 01-udevd-config.patch --]
[-- Type: text/plain, Size: 5737 bytes --]

===== Makefile 1.94 vs edited =====
--- 1.94/Makefile	Thu Jan 29 17:46:29 2004
+++ edited/Makefile	Sun Feb  1 18:32:57 2004
@@ -38,6 +38,7 @@
 INSTALL_DIR =	/usr/local/bin
 RELEASE_NAME =	$(ROOT)-$(VERSION)
 LOCAL_CFG_DIR =	etc/udev
+HOTPLUG_EXEC =	$(ROOT)
 
 DESTDIR =
 # override this to make udev look in a different location for it's config files
@@ -232,8 +233,10 @@
 	@echo \#define UDEV_CONFIG_FILE	\"$(configdir)\udev.conf\" >> $@
 	@echo \#define UDEV_RULES_FILE	\"$(configdir)\udev.rules\" >> $@
 	@echo \#define UDEV_PERMISSION_FILE	\"$(configdir)\udev.permissions\" >> $@
-	@echo \#define UDEV_BIN		\"$(PWD)/udev\" >> $@
-	@echo \#define UDEVD_BIN	\"$(PWD)/udevd\" >> $@
+	@echo \#define UDEV_BIN		\"$(DESTDIR)$(sbindir)/udev\" >> $@
+	@echo \#define UDEVD_BIN	\"$(DESTDIR)$(sbindir)/udevd\" >> $@
+	@echo \#define UDEVD_SOCK	\"$(udevdir)/\.udevd.sock\" >> $@
+	@echo \#define UDEVD_LOCK	\"$(udevdir)/\.udevd.lock\" >> $@
 
 # config files automatically generated
 GEN_CONFIGS =	$(LOCAL_CFG_DIR)/udev.conf
@@ -338,6 +341,8 @@
 	$(INSTALL) -d $(DESTDIR)$(udevdir)
 	$(INSTALL) -d $(DESTDIR)$(hotplugdir)
 	$(INSTALL_PROGRAM) -D $(ROOT) $(DESTDIR)$(sbindir)/$(ROOT)
+	$(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON)
+	$(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER)
 	$(INSTALL_PROGRAM) -D $(HELPER) $(DESTDIR)$(sbindir)/$(HELPER)
 	@if [ "x$(USE_LSB)" = "xtrue" ]; then \
 		$(INSTALL_PROGRAM) -D etc/init.d/udev.init.LSB $(DESTDIR)$(initdir)/udev; \
@@ -347,8 +352,8 @@
 	fi
 	$(INSTALL_DATA) -D udev.8 $(DESTDIR)$(mandir)/man8/udev.8
 	$(INSTALL_DATA) -D udevinfo.8 $(DESTDIR)$(mandir)/man8/udevinfo.8
-	- rm -f $(DESTDIR)$(hotplugdir)/udev.hotplug
-	- ln -f -s $(sbindir)/$(ROOT) $(DESTDIR)$(hotplugdir)/udev.hotplug
+	- rm -f $(DESTDIR)$(hotplugdir)/$(HOTPLUG_EXEC).hotplug
+	- ln -f -s $(sbindir)/$(HOTPLUG_EXEC) $(DESTDIR)$(hotplugdir)/$(HOTPLUG_EXEC).hotplug
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
@@ -356,7 +361,7 @@
 	done ; \
 
 uninstall: uninstall-dbus-policy
-	- rm $(hotplugdir)/udev.hotplug
+	- rm $(hotplugdir)/$(HOTPLUG_EXEC).hotplug
 	- rm $(configdir)/udev.permissions
 	- rm $(configdir)/udev.rules
 	- rm $(configdir)/udev.conf
@@ -364,6 +369,8 @@
 	- rm $(mandir)/man8/udev.8
 	- rm $(mandir)/man8/udevinfo.8
 	- rm $(sbindir)/$(ROOT)
+	- rm $(sbindir)/$(DAEMON)
+	- rm $(sbindir)/$(SENDER)
 	- rm $(sbindir)/$(HELPER)
 	- rmdir $(hotplugdir)
 	- rmdir $(configdir)
===== udevd.c 1.8 vs edited =====
--- 1.8/udevd.c	Sat Jan 31 04:08:44 2004
+++ edited/udevd.c	Sun Feb  1 17:59:29 2004
@@ -71,7 +71,6 @@
 	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-/* allocates a new message */
 static struct hotplug_msg *msg_create(void)
 {
 	struct hotplug_msg *new_msg;
@@ -81,10 +80,15 @@
 		dbg("error malloc");
 		return NULL;
 	}
-	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
 	return new_msg;
 }
 
+static void msg_delete(struct hotplug_msg *msg)
+{
+	if (msg != NULL)
+		free(msg);
+}
+
 /* orders the message in the queue by sequence number */
 static void msg_queue_insert(struct hotplug_msg *msg)
 {
@@ -143,7 +147,7 @@
 	list_del_init(&msg->list);
 	pthread_mutex_unlock(&running_lock);
 
-	free(msg);
+	msg_delete(msg);
 
 	/* signal queue activity to exec manager */
 	pthread_mutex_lock(&exec_active_lock);
@@ -289,6 +293,7 @@
 
 	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
 		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		msg_delete(msg);
 		goto exit;
 	}
 
@@ -307,7 +312,7 @@
 		case SIGINT:
 		case SIGTERM:
 			unlink(UDEVD_LOCK);
-			unlink(UDEVD_SOCKET);
+			unlink(UDEVD_SOCK);
 			exit(20 + signum);
 			break;
 		default:
@@ -320,7 +325,6 @@
 	char string[50];
 	int lock_file;
 
-	/* see if we can open */
 	lock_file = open(UDEVD_LOCK, O_RDWR | O_CREAT, 0x640);
 	if (lock_file < 0)
 		return -1;
@@ -359,9 +363,9 @@
 
 	memset(&saddr, 0x00, sizeof(saddr));
 	saddr.sun_family = AF_LOCAL;
-	strcpy(saddr.sun_path, UDEVD_SOCKET);
+	strcpy(saddr.sun_path, UDEVD_SOCK);
 
-	unlink(UDEVD_SOCKET);
+	unlink(UDEVD_SOCK);
 	ssock = socket(AF_LOCAL, SOCK_STREAM, 0);
 	if (ssock == -1) {
 		dbg("error getting socket");
@@ -399,14 +403,13 @@
 	while (1) {
 		csock = accept(ssock, &caddr, &clen);
 		if (csock < 0) {
-			if (errno == EINTR)
-				continue;
 			dbg("client accept failed\n");
+			continue;
 		}
 		pthread_create(&cli_tid, &thr_attr, client_threads, (void *) csock);
 	}
 exit:
 	close(ssock);
-	unlink(UDEVD_SOCKET);
+	unlink(UDEVD_SOCK);
 	exit(1);
 }
===== udevd.h 1.5 vs edited =====
--- 1.5/udevd.h	Sat Jan 31 04:12:52 2004
+++ edited/udevd.h	Sun Feb  1 18:20:40 2004
@@ -24,18 +24,9 @@
 
 #include "list.h"
 
-/*
- * FIXME: udev_root is post compile configurable and may also be
- * mounted over at any time and /var/run/ and /tmp/ is unusable,
- * cause it's cleaned at system startup, long _after_ udevd is
- * already running. Should we use udev_init_config()?
- */
-
-#define UDEV_MAGIC			"udev_" UDEV_VERSION
+#define UDEV_MAGIC			"udevd_" UDEV_VERSION
 #define EVENT_TIMEOUT_SEC		5
 #define UDEVSEND_CONNECT_RETRY		20 /* x 100 millisec */
-#define UDEVD_SOCKET			UDEV_ROOT ".udevd.socket"
-#define UDEVD_LOCK			UDEV_ROOT ".udevd.pid"
 
 struct hotplug_msg {
 	char magic[20];
===== udevsend.c 1.9 vs edited =====
--- 1.9/udevsend.c	Sat Jan 31 03:53:31 2004
+++ edited/udevsend.c	Sun Feb  1 17:59:56 2004
@@ -159,7 +159,7 @@
 
 	memset(&saddr, 0x00, sizeof(saddr));
 	saddr.sun_family = AF_LOCAL;
-	strcpy(saddr.sun_path, UDEVD_SOCKET);
+	strcpy(saddr.sun_path, UDEVD_SOCK);
 
 	/* try to connect, if it fails start daemon */
 	retval = connect(sock, &saddr, sizeof(saddr));

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (16 preceding siblings ...)
  2004-02-01 18:16 ` Kay Sievers
@ 2004-02-02  2:19 ` Kay Sievers
  2004-02-02  8:21 ` Greg KH
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-02  2:19 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 1111 bytes --]

On Sun, Feb 01, 2004 at 07:16:36PM +0100, Kay Sievers wrote:
> On Sun, Feb 01, 2004 at 01:08:54AM -0800, Greg KH wrote:
> > On Sat, Jan 31, 2004 at 03:42:20AM +0100, Kay Sievers wrote:
> > > 
> > > Next cleaned up version. Hey, nobody wants to try it :)
> > > 
> > > Works for me, It's funny if I connect/disconnect my 4in1-usb-flash-reader
> > > every two seconds. The 2.6 usb rocks! I can connect/diconnect a hub with 3
> > > devices plugged in every second and don't run into any problem but a _very_
> > > big udevd queue.
> > 
> > Very sorry for the delay, been busy with other work these past few days.
> > 
> > I've applied this patch, and pushed it to the repo.  I'll try to test it
> > some more myself early next week, and let you know how it goes.
> 
> Here is a small cleanup and better Makefile integration.
> udevd and udevsender are now installed. Just switch HOTPLUG_EXEC from ROOT
> to SENDER before install and udevsend will be called.
> 
> We may add the location of the socket and lock file to the config,
> if this is needed.

Same patch with a fix for the stack size setting.

thanks,
Kay

[-- Attachment #2: 01-udevd-config.patch --]
[-- Type: text/plain, Size: 6072 bytes --]

===== Makefile 1.94 vs edited =====
--- 1.94/Makefile	Thu Jan 29 17:46:29 2004
+++ edited/Makefile	Mon Feb  2 02:44:27 2004
@@ -38,6 +38,7 @@
 INSTALL_DIR =	/usr/local/bin
 RELEASE_NAME =	$(ROOT)-$(VERSION)
 LOCAL_CFG_DIR =	etc/udev
+HOTPLUG_EXEC =	$(ROOT)
 
 DESTDIR =
 # override this to make udev look in a different location for it's config files
@@ -232,8 +233,10 @@
 	@echo \#define UDEV_CONFIG_FILE	\"$(configdir)\udev.conf\" >> $@
 	@echo \#define UDEV_RULES_FILE	\"$(configdir)\udev.rules\" >> $@
 	@echo \#define UDEV_PERMISSION_FILE	\"$(configdir)\udev.permissions\" >> $@
-	@echo \#define UDEV_BIN		\"$(PWD)/udev\" >> $@
-	@echo \#define UDEVD_BIN	\"$(PWD)/udevd\" >> $@
+	@echo \#define UDEV_BIN		\"$(DESTDIR)$(sbindir)/udev\" >> $@
+	@echo \#define UDEVD_BIN	\"$(DESTDIR)$(sbindir)/udevd\" >> $@
+	@echo \#define UDEVD_SOCK	\"$(udevdir)/\.udevd.sock\" >> $@
+	@echo \#define UDEVD_LOCK	\"$(udevdir)/\.udevd.lock\" >> $@
 
 # config files automatically generated
 GEN_CONFIGS =	$(LOCAL_CFG_DIR)/udev.conf
@@ -338,6 +341,8 @@
 	$(INSTALL) -d $(DESTDIR)$(udevdir)
 	$(INSTALL) -d $(DESTDIR)$(hotplugdir)
 	$(INSTALL_PROGRAM) -D $(ROOT) $(DESTDIR)$(sbindir)/$(ROOT)
+	$(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON)
+	$(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER)
 	$(INSTALL_PROGRAM) -D $(HELPER) $(DESTDIR)$(sbindir)/$(HELPER)
 	@if [ "x$(USE_LSB)" = "xtrue" ]; then \
 		$(INSTALL_PROGRAM) -D etc/init.d/udev.init.LSB $(DESTDIR)$(initdir)/udev; \
@@ -347,8 +352,8 @@
 	fi
 	$(INSTALL_DATA) -D udev.8 $(DESTDIR)$(mandir)/man8/udev.8
 	$(INSTALL_DATA) -D udevinfo.8 $(DESTDIR)$(mandir)/man8/udevinfo.8
-	- rm -f $(DESTDIR)$(hotplugdir)/udev.hotplug
-	- ln -f -s $(sbindir)/$(ROOT) $(DESTDIR)$(hotplugdir)/udev.hotplug
+	- rm -f $(DESTDIR)$(hotplugdir)/$(HOTPLUG_EXEC).hotplug
+	- ln -f -s $(sbindir)/$(HOTPLUG_EXEC) $(DESTDIR)$(hotplugdir)/udev.hotplug
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
@@ -364,6 +369,8 @@
 	- rm $(mandir)/man8/udev.8
 	- rm $(mandir)/man8/udevinfo.8
 	- rm $(sbindir)/$(ROOT)
+	- rm $(sbindir)/$(DAEMON)
+	- rm $(sbindir)/$(SENDER)
 	- rm $(sbindir)/$(HELPER)
 	- rmdir $(hotplugdir)
 	- rmdir $(configdir)
===== udevd.c 1.8 vs edited =====
--- 1.8/udevd.c	Sat Jan 31 04:08:44 2004
+++ edited/udevd.c	Mon Feb  2 02:41:34 2004
@@ -19,6 +19,7 @@
  *
  */
 
+#include <pthread.h>
 #include <stddef.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -33,7 +34,6 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <pthread.h>
 
 #include "list.h"
 #include "udev.h"
@@ -71,7 +71,6 @@
 	    msg->seqnum, msg->action, msg->devpath, msg->subsystem);
 }
 
-/* allocates a new message */
 static struct hotplug_msg *msg_create(void)
 {
 	struct hotplug_msg *new_msg;
@@ -81,10 +80,15 @@
 		dbg("error malloc");
 		return NULL;
 	}
-	memset(new_msg, 0x00, sizeof(struct hotplug_msg));
 	return new_msg;
 }
 
+static void msg_delete(struct hotplug_msg *msg)
+{
+	if (msg != NULL)
+		free(msg);
+}
+
 /* orders the message in the queue by sequence number */
 static void msg_queue_insert(struct hotplug_msg *msg)
 {
@@ -143,7 +147,7 @@
 	list_del_init(&msg->list);
 	pthread_mutex_unlock(&running_lock);
 
-	free(msg);
+	msg_delete(msg);
 
 	/* signal queue activity to exec manager */
 	pthread_mutex_lock(&exec_active_lock);
@@ -289,6 +293,7 @@
 
 	if (strncmp(msg->magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
 		dbg("message magic '%s' doesn't match, ignore it", msg->magic);
+		msg_delete(msg);
 		goto exit;
 	}
 
@@ -307,7 +312,7 @@
 		case SIGINT:
 		case SIGTERM:
 			unlink(UDEVD_LOCK);
-			unlink(UDEVD_SOCKET);
+			unlink(UDEVD_SOCK);
 			exit(20 + signum);
 			break;
 		default:
@@ -320,7 +325,6 @@
 	char string[50];
 	int lock_file;
 
-	/* see if we can open */
 	lock_file = open(UDEVD_LOCK, O_RDWR | O_CREAT, 0x640);
 	if (lock_file < 0)
 		return -1;
@@ -359,9 +363,9 @@
 
 	memset(&saddr, 0x00, sizeof(saddr));
 	saddr.sun_family = AF_LOCAL;
-	strcpy(saddr.sun_path, UDEVD_SOCKET);
+	strcpy(saddr.sun_path, UDEVD_SOCK);
 
-	unlink(UDEVD_SOCKET);
+	unlink(UDEVD_SOCK);
 	ssock = socket(AF_LOCAL, SOCK_STREAM, 0);
 	if (ssock == -1) {
 		dbg("error getting socket");
@@ -389,6 +393,7 @@
 	/* set default attributes for created threads */
 	pthread_attr_init(&thr_attr);
 	pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
+	pthread_attr_setstacksize(&thr_attr, 16 * 1024);
 
 	/* init queue management */
 	pthread_create(&mgr_msg_tid, &thr_attr, msg_queue_manager, NULL);
@@ -399,14 +404,13 @@
 	while (1) {
 		csock = accept(ssock, &caddr, &clen);
 		if (csock < 0) {
-			if (errno == EINTR)
-				continue;
 			dbg("client accept failed\n");
+			continue;
 		}
 		pthread_create(&cli_tid, &thr_attr, client_threads, (void *) csock);
 	}
 exit:
 	close(ssock);
-	unlink(UDEVD_SOCKET);
+	unlink(UDEVD_SOCK);
 	exit(1);
 }
===== udevd.h 1.5 vs edited =====
--- 1.5/udevd.h	Sat Jan 31 04:12:52 2004
+++ edited/udevd.h	Mon Feb  2 02:40:48 2004
@@ -24,18 +24,9 @@
 
 #include "list.h"
 
-/*
- * FIXME: udev_root is post compile configurable and may also be
- * mounted over at any time and /var/run/ and /tmp/ is unusable,
- * cause it's cleaned at system startup, long _after_ udevd is
- * already running. Should we use udev_init_config()?
- */
-
-#define UDEV_MAGIC			"udev_" UDEV_VERSION
+#define UDEV_MAGIC			"udevd_" UDEV_VERSION
 #define EVENT_TIMEOUT_SEC		5
 #define UDEVSEND_CONNECT_RETRY		20 /* x 100 millisec */
-#define UDEVD_SOCKET			UDEV_ROOT ".udevd.socket"
-#define UDEVD_LOCK			UDEV_ROOT ".udevd.pid"
 
 struct hotplug_msg {
 	char magic[20];
===== udevsend.c 1.9 vs edited =====
--- 1.9/udevsend.c	Sat Jan 31 03:53:31 2004
+++ edited/udevsend.c	Mon Feb  2 02:40:48 2004
@@ -159,7 +159,7 @@
 
 	memset(&saddr, 0x00, sizeof(saddr));
 	saddr.sun_family = AF_LOCAL;
-	strcpy(saddr.sun_path, UDEVD_SOCKET);
+	strcpy(saddr.sun_path, UDEVD_SOCK);
 
 	/* try to connect, if it fails start daemon */
 	retval = connect(sock, &saddr, sizeof(saddr));

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (17 preceding siblings ...)
  2004-02-02  2:19 ` Kay Sievers
@ 2004-02-02  8:21 ` Greg KH
  2004-02-02 11:50 ` Kay Sievers
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-02-02  8:21 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Feb 02, 2004 at 03:19:22AM +0100, Kay Sievers wrote:
> 
> Same patch with a fix for the stack size setting.

Nice, applied.

I also cleaned up the way the logging code works, so that now we can see
what program is spitting out what messages in the syslog.

Also, udevsend can _almost_ be built with klibc.  Any reason we have to
use a struct sockaddr_un instead of just a struct sockaddr?  If that is
changed than only udevd would rely on glibc.

I don't mind udevd using glibc, I just want the programs that get run a
lot of different times (udev and udevsend) to be as small as possible to
get the best cache results.  As udevd sticks around all the time, it's
not as important.  Sound sane to you?

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (18 preceding siblings ...)
  2004-02-02  8:21 ` Greg KH
@ 2004-02-02 11:50 ` Kay Sievers
  2004-02-02 18:45 ` Greg KH
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-02 11:50 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 1185 bytes --]

On Mon, Feb 02, 2004 at 12:21:39AM -0800, Greg KH wrote:
> On Mon, Feb 02, 2004 at 03:19:22AM +0100, Kay Sievers wrote:
> > 
> > Same patch with a fix for the stack size setting.
> 
> Nice, applied.
> 
> I also cleaned up the way the logging code works, so that now we can see
> what program is spitting out what messages in the syslog.

Fine, I've missed it too sometimes.
We may include unistd.h for get_pid()?


> Also, udevsend can _almost_ be built with klibc.  Any reason we have to
> use a struct sockaddr_un instead of just a struct sockaddr?  If that is
> changed than only udevd would rely on glibc.

The sockaddr doesn't contain the 108 char long pathname of the socket file.


> I don't mind udevd using glibc, I just want the programs that get run a
> lot of different times (udev and udevsend) to be as small as possible to
> get the best cache results.  As udevd sticks around all the time, it's
> not as important.  Sound sane to you?

Oh, nice. Good idea.
I have two alternatives attached:

  01-udevsend-klibc.patch
    not the nicest, but it works

  01-klibc-unix-domain.patch
    clean, but touches klibc sources by inserting the missing header file


thanks,
Kay

[-- Attachment #2: 01-klibc-unix-domain.patch --]
[-- Type: text/plain, Size: 1469 bytes --]

diff -Nru a/Makefile b/Makefile
--- a/Makefile	Mon Feb  2 12:33:54 2004
+++ b/Makefile	Mon Feb  2 12:33:54 2004
@@ -161,12 +161,12 @@
 	CFLAGS += $(WARNINGS) -I$(GCCINCDIR)
 	LIB_OBJS = -lc
 	LDFLAGS =
-	UDEVD = $(DAEMON) $(SENDER)
+	UDEVD = $(DAEMON)
 endif
 
 CFLAGS += -I$(PWD)/libsysfs
 
-all: $(ROOT) $(UDEVD) $(HELPER)
+all: $(ROOT) $(SENDER) $(UDEVD) $(HELPER)
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
diff -Nru a/klibc/klibc/include/sys/un.h b/klibc/klibc/include/sys/un.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/klibc/klibc/include/sys/un.h	Mon Feb  2 12:33:54 2004
@@ -0,0 +1,10 @@
+/*
+ * sys/un.h
+ */
+
+#ifndef _UN_H
+#define _UN_H
+
+#include <linux/un.h>
+
+#endif /* _UN_H */
diff -Nru a/udevsend.c b/udevsend.c
--- a/udevsend.c	Mon Feb  2 12:33:54 2004
+++ b/udevsend.c	Mon Feb  2 12:33:54 2004
@@ -163,7 +163,7 @@
 	strcpy(saddr.sun_path, UDEVD_SOCK);
 
 	/* try to connect, if it fails start daemon */
-	retval = connect(sock, &saddr, sizeof(saddr));
+	retval = connect(sock, (struct sockaddr *) &saddr, sizeof(saddr));
 	if (retval != -1) {
 		goto send;
 	} else {
@@ -182,7 +182,7 @@
 	tspec.tv_nsec = 100000000;  /* 100 millisec */
 	loop = UDEVSEND_CONNECT_RETRY;
 	while (loop--) {
-		retval = connect(sock, &saddr, sizeof(saddr));
+		retval = connect(sock, (struct sockaddr *) &saddr, sizeof(saddr));
 		if (retval != -1)
 			goto send;
 		else

[-- Attachment #3: 01-udevsend-klibc.patch --]
[-- Type: text/plain, Size: 1431 bytes --]

===== Makefile 1.96 vs edited =====
--- 1.96/Makefile	Mon Feb  2 09:19:41 2004
+++ edited/Makefile	Mon Feb  2 11:23:22 2004
@@ -161,12 +161,12 @@
 	CFLAGS += $(WARNINGS) -I$(GCCINCDIR)
 	LIB_OBJS = -lc
 	LDFLAGS =
-	UDEVD = $(DAEMON) $(SENDER)
+	UDEVD = $(DAEMON)
 endif
 
 CFLAGS += -I$(PWD)/libsysfs
 
-all: $(ROOT) $(UDEVD) $(HELPER)
+all: $(ROOT) $(SENDER) $(UDEVD) $(HELPER)
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) LD="$(LD)" SYSFS="$(SYSFS)" \
===== udevsend.c 1.12 vs edited =====
--- 1.12/udevsend.c	Mon Feb  2 09:29:03 2004
+++ edited/udevsend.c	Mon Feb  2 11:15:55 2004
@@ -25,7 +25,11 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#ifdef __KLIBC__
+#include <linux/un.h>
+#else
 #include <sys/un.h>
+#endif
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -163,7 +167,7 @@
 	strcpy(saddr.sun_path, UDEVD_SOCK);
 
 	/* try to connect, if it fails start daemon */
-	retval = connect(sock, &saddr, sizeof(saddr));
+	retval = connect(sock, (struct sockaddr *) &saddr, sizeof(saddr));
 	if (retval != -1) {
 		goto send;
 	} else {
@@ -182,7 +186,7 @@
 	tspec.tv_nsec = 100000000;  /* 100 millisec */
 	loop = UDEVSEND_CONNECT_RETRY;
 	while (loop--) {
-		retval = connect(sock, &saddr, sizeof(saddr));
+		retval = connect(sock, (struct sockaddr *) &saddr, sizeof(saddr));
 		if (retval != -1)
 			goto send;
 		else

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (19 preceding siblings ...)
  2004-02-02 11:50 ` Kay Sievers
@ 2004-02-02 18:45 ` Greg KH
  2004-02-02 21:36 ` Kay Sievers
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-02-02 18:45 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Feb 02, 2004 at 12:50:24PM +0100, Kay Sievers wrote:
> On Mon, Feb 02, 2004 at 12:21:39AM -0800, Greg KH wrote:
> > On Mon, Feb 02, 2004 at 03:19:22AM +0100, Kay Sievers wrote:
> > > 
> > > Same patch with a fix for the stack size setting.
> > 
> > Nice, applied.
> > 
> > I also cleaned up the way the logging code works, so that now we can see
> > what program is spitting out what messages in the syslog.
> 
> Fine, I've missed it too sometimes.
> We may include unistd.h for get_pid()?

Is it needed for you to build?  It seems to work for me :)

> > Also, udevsend can _almost_ be built with klibc.  Any reason we have to
> > use a struct sockaddr_un instead of just a struct sockaddr?  If that is
> > changed than only udevd would rely on glibc.
> 
> The sockaddr doesn't contain the 108 char long pathname of the socket file.

Ah, ok, that makes more sense.

> > I don't mind udevd using glibc, I just want the programs that get run a
> > lot of different times (udev and udevsend) to be as small as possible to
> > get the best cache results.  As udevd sticks around all the time, it's
> > not as important.  Sound sane to you?
> 
> Oh, nice. Good idea.
> I have two alternatives attached:
> 
>   01-udevsend-klibc.patch
>     not the nicest, but it works
> 
>   01-klibc-unix-domain.patch
>     clean, but touches klibc sources by inserting the missing header file

I applied this version, and then cleaned up udevsend a bit more so now
it builds a 2.5kb binary using klibc.  That's very nice.

thanks,

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (20 preceding siblings ...)
  2004-02-02 18:45 ` Greg KH
@ 2004-02-02 21:36 ` Kay Sievers
  2004-02-03  1:26 ` Greg KH
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-02 21:36 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Feb 02, 2004 at 10:45:29AM -0800, Greg KH wrote:
> On Mon, Feb 02, 2004 at 12:50:24PM +0100, Kay Sievers wrote:
> > On Mon, Feb 02, 2004 at 12:21:39AM -0800, Greg KH wrote:
> > > On Mon, Feb 02, 2004 at 03:19:22AM +0100, Kay Sievers wrote:
> > > > 
> > > > Same patch with a fix for the stack size setting.
> > > 
> > > Nice, applied.
> > > 
> > > I also cleaned up the way the logging code works, so that now we can see
> > > what program is spitting out what messages in the syslog.
> > 
> > Fine, I've missed it too sometimes.
> > We may include unistd.h for get_pid()?
> 
> Is it needed for you to build?  It seems to work for me :)

No, it works without it, cause the linker finds the symbol later.
But we use the function in udev.c and udevdb.c, so I thought we
should include the header for the prototype:

  In file included from udevdb.c:38:
  logging.h: In function `init_logging':
  logging.h:76: warning: implicit declaration of function `getpid'


Does the daemon work for you?
I would expect that you have more devices to connect than me.
I have only a USB-flash-reader and a simple webcam :)

Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (21 preceding siblings ...)
  2004-02-02 21:36 ` Kay Sievers
@ 2004-02-03  1:26 ` Greg KH
  2004-02-03  6:43 ` Ling, Xiaofeng
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-02-03  1:26 UTC (permalink / raw)
  To: linux-hotplug

On Mon, Feb 02, 2004 at 10:36:44PM +0100, Kay Sievers wrote:
> 
> No, it works without it, cause the linker finds the symbol later.
> But we use the function in udev.c and udevdb.c, so I thought we
> should include the header for the prototype:
> 
>   In file included from udevdb.c:38:
>   logging.h: In function `init_logging':
>   logging.h:76: warning: implicit declaration of function `getpid'

Hm, I don't see that on my build.  Must be using different versions of
gcc or something.  Send me a patch and I'll add it.

> Does the daemon work for you?

It does, quite nicely.  I just tested a bunch of different devices, very
nice job.

> I would expect that you have more devices to connect than me.
> I have only a USB-flash-reader and a simple webcam :)

Well, I do have a box full of odd usb devices around here.  I'll beat on
this some more tomorrow morning and then get a release out there for
the world to test too.

Very nice job.

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* RE: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (22 preceding siblings ...)
  2004-02-03  1:26 ` Greg KH
@ 2004-02-03  6:43 ` Ling, Xiaofeng
  2004-02-03 20:12 ` Kay Sievers
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Ling, Xiaofeng @ 2004-02-03  6:43 UTC (permalink / raw)
  To: linux-hotplug



> -----Original Message-----
> From: linux-hotplug-devel-admin@lists.sourceforge.net 
> [mailto:linux-hotplug-devel-admin@lists.sourceforge.net] On 
> Behalf Of Greg KH
> Sent: 2004Äê1ÔÂ27ÈÕ 3:28
> To: Kay Sievers
> Cc: linux-hotplug-devel@lists.sourceforge.net
> Subject: Re: [patch] udevd - cleanup and better timeout handling
> 
> 
> > > 
> > > But how will we keep track of that?  It's probably easier just to 
> > > wait for each one to finish, right?
> > 
> > We leave the message in the queue until we reach the 
> SIGCHLD for this 
> > pid. So we can search the queue if we are already working on this 
> > devpath, and delay the new exec until the former exec comes back.
> 
> Ok, if that isn't too much trouble.
> 
> > Is it feasible to run in parallel for different paths, or can you 
> > think of any problem?
> 
Is it safe to run parallel or unsequential for different path? I worry about it. Some devices
like usb disk,  there will be a sequence of event  for different path when pluging in, like
/class/scsi_device/0:0:0:0  
/class/scsi_host/host0 
block/sda
block/sda1
block/sda2,
although currently, I can not give out an bad example, but I still worry that there maybe have
in future.




-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (23 preceding siblings ...)
  2004-02-03  6:43 ` Ling, Xiaofeng
@ 2004-02-03 20:12 ` Kay Sievers
  2004-02-04  0:56 ` Greg KH
                   ` (5 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-03 20:12 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 687 bytes --]

On Mon, Feb 02, 2004 at 05:26:45PM -0800, Greg KH wrote:
> On Mon, Feb 02, 2004 at 10:36:44PM +0100, Kay Sievers wrote:
> > 
> > No, it works without it, cause the linker finds the symbol later.
> > But we use the function in udev.c and udevdb.c, so I thought we
> > should include the header for the prototype:
> > 
> >   In file included from udevdb.c:38:
> >   logging.h: In function `init_logging':
> >   logging.h:76: warning: implicit declaration of function `getpid'
> 
> Hm, I don't see that on my build.  Must be using different versions of
> gcc or something.  Send me a patch and I'll add it.

This includes the missing header for the use of getpid in logging.h.

thanks,
Kay

[-- Attachment #2: 01-include-used-funtion.patch --]
[-- Type: text/plain, Size: 235 bytes --]

===== logging.h 1.6 vs edited =====
--- 1.6/logging.h	Mon Feb  2 09:22:01 2004
+++ edited/logging.h	Tue Feb  3 21:06:26 2004
@@ -31,6 +31,7 @@
 
 #ifdef LOG
 #include <stdarg.h>
+#include <unistd.h>
 #include <syslog.h>
 
 #undef info

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (24 preceding siblings ...)
  2004-02-03 20:12 ` Kay Sievers
@ 2004-02-04  0:56 ` Greg KH
  2004-02-08  9:43 ` Olaf Hering
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Greg KH @ 2004-02-04  0:56 UTC (permalink / raw)
  To: linux-hotplug

On Tue, Feb 03, 2004 at 09:12:42PM +0100, Kay Sievers wrote:
> 
> This includes the missing header for the use of getpid in logging.h.
> 

Thanks, applied.

greg k-h


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (25 preceding siblings ...)
  2004-02-04  0:56 ` Greg KH
@ 2004-02-08  9:43 ` Olaf Hering
  2004-02-08 15:22 ` Kay Sievers
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Olaf Hering @ 2004-02-08  9:43 UTC (permalink / raw)
  To: linux-hotplug

 On Sat, Jan 31, Kay Sievers wrote:

> === udevd.c 1.7 vs edited ==> --- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
> +++ edited/udevd.c	Sat Jan 31 03:08:44 2004

> +#include <sys/un.h>

this breaks compilation against klibc. Should udevd run in initramfs?
Probably not. Better dont compile it if USE_KLIBC=true
Or provide a sys/un.h in klibc.

-- 
USB is for mice, FireWire is for men!

sUse lINUX ag, n√úRNBERG


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (26 preceding siblings ...)
  2004-02-08  9:43 ` Olaf Hering
@ 2004-02-08 15:22 ` Kay Sievers
  2004-02-08 15:40 ` Olaf Hering
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-08 15:22 UTC (permalink / raw)
  To: linux-hotplug

On Sun, Feb 08, 2004 at 10:43:32AM +0100, Olaf Hering wrote:
>  On Sat, Jan 31, Kay Sievers wrote:
> 
> > === udevd.c 1.7 vs edited ==> > --- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
> > +++ edited/udevd.c	Sat Jan 31 03:08:44 2004
> 
> > +#include <sys/un.h>
> 
> this breaks compilation against klibc. Should udevd run in initramfs?
> Probably not. Better dont compile it if USE_KLIBC=true
> Or provide a sys/un.h in klibc.

Hey, is this post from today :)
It's already fixed since 6 days.

  http://linuxusb.bkbits.net:8080/udev/cset@1.497?nav=index.html|ChangeSet@-8d

Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (27 preceding siblings ...)
  2004-02-08 15:22 ` Kay Sievers
@ 2004-02-08 15:40 ` Olaf Hering
  2004-02-08 15:57 ` Kay Sievers
  2004-02-08 16:09 ` Olaf Hering
  30 siblings, 0 replies; 32+ messages in thread
From: Olaf Hering @ 2004-02-08 15:40 UTC (permalink / raw)
  To: linux-hotplug

 On Sun, Feb 08, Kay Sievers wrote:

> On Sun, Feb 08, 2004 at 10:43:32AM +0100, Olaf Hering wrote:
> >  On Sat, Jan 31, Kay Sievers wrote:
> > 
> > > === udevd.c 1.7 vs edited ==> > > --- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
> > > +++ edited/udevd.c	Sat Jan 31 03:08:44 2004
> > 
> > > +#include <sys/un.h>
> > 
> > this breaks compilation against klibc. Should udevd run in initramfs?
> > Probably not. Better dont compile it if USE_KLIBC=true
> > Or provide a sys/un.h in klibc.
> 
> Hey, is this post from today :)
> It's already fixed since 6 days.

Not in my copy. Still need this patch.
The install rule needs also an update.

--- udev-016.bk.orig/Makefile   2004-02-08 10:55:43.000000000 +0100
+++ udev-016.bk/Makefile        2004-02-08 11:04:35.559002703 +0100
@@ -157,6 +157,7 @@ ifeq ($(strip $(USE_KLIBC)),true)
                -I$(LINUX_INCLUDE_DIR)
        LIB_OBJS         LDFLAGS = --static --nostdlib -nostartfiles -nodefaultlibs
+       UDEVSENDER        UDEVD  else   
        WARNINGS += -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
@@ -165,12 +166,13 @@ else
        CFLAGS += $(WARNINGS) -I$(GCCINCDIR)
        LIB_OBJS = -lc
        LDFLAGS +       UDEVSENDER= $(SENDER)
        UDEVD = $(DAEMON)
 endif

 CFLAGS += -I$(PWD)/libsysfs

-all: $(ROOT) $(SENDER) $(UDEVD) $(HELPER)
+all: $(ROOT) $(UDEVSENDER) $(UDEVD) $(HELPER)
        @extras="$(EXTRAS)" ; for target in $$extras ; do \
                echo $$target ; \
                $(MAKE) prefix=$(prefix) \
@@ -261,11 +263,11 @@ $(HELPER): $(HEADERS) udevinfo.o $(OBJS)
        $(LD) $(LDFLAGS) -o $@ $(CRT0) udevinfo.o udev_config.o udevdb.o $(SYSFS) $(TDB) $(LIB_OBJS) $(ARCH_LIB_OBJS)
        $(STRIPCMD) $@

-$(DAEMON): udevd.h $(GEN_HEADERS) udevd.o
+$(UDEVD): udevd.h $(GEN_HEADERS) udevd.o
        $(LD) $(LDFLAGS) -o $@ $(CRT0) udevd.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
        $(STRIPCMD) $@

-$(SENDER): udevd.h $(GEN_HEADERS) udevsend.o
+$(UDEVSENDER): udevd.h $(GEN_HEADERS) udevsend.o
        $(LD) $(LDFLAGS) -o $@ $(CRT0) udevsend.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
        $(STRIPCMD) $@




-- 
USB is for mice, FireWire is for men!

sUse lINUX ag, n√úRNBERG


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (28 preceding siblings ...)
  2004-02-08 15:40 ` Olaf Hering
@ 2004-02-08 15:57 ` Kay Sievers
  2004-02-08 16:09 ` Olaf Hering
  30 siblings, 0 replies; 32+ messages in thread
From: Kay Sievers @ 2004-02-08 15:57 UTC (permalink / raw)
  To: linux-hotplug

On Sun, Feb 08, 2004 at 04:40:28PM +0100, Olaf Hering wrote:
>  On Sun, Feb 08, Kay Sievers wrote:
> 
> > On Sun, Feb 08, 2004 at 10:43:32AM +0100, Olaf Hering wrote:
> > >  On Sat, Jan 31, Kay Sievers wrote:
> > > 
> > > > === udevd.c 1.7 vs edited ==> > > > --- 1.7/udevd.c	Wed Jan 28 19:52:44 2004
> > > > +++ edited/udevd.c	Sat Jan 31 03:08:44 2004
> > > 
> > > > +#include <sys/un.h>
> > > 
> > > this breaks compilation against klibc. Should udevd run in initramfs?
> > > Probably not. Better dont compile it if USE_KLIBC=true
> > > Or provide a sys/un.h in klibc.
> > 
> > Hey, is this post from today :)
> > It's already fixed since 6 days.
> 
> Not in my copy.

Huh, you don't have sys/un.h in your copy?


> Still need this patch.
> The install rule needs also an update.

But, we do want to compile udevsend with klibc if it is used.
udevd will be compiled while "make install" using libc,
not nice but it works.

Kay


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

* Re: [patch] udevd - cleanup and better timeout handling
  2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
                   ` (29 preceding siblings ...)
  2004-02-08 15:57 ` Kay Sievers
@ 2004-02-08 16:09 ` Olaf Hering
  30 siblings, 0 replies; 32+ messages in thread
From: Olaf Hering @ 2004-02-08 16:09 UTC (permalink / raw)
  To: linux-hotplug

 On Sun, Feb 08, Kay Sievers wrote:

> Huh, you don't have sys/un.h in your copy?

klibc-0.103.tar.bz2 doesnt have it, but I see it now in the udev bk
tree.
> 
> > Still need this patch.
> > The install rule needs also an update.
> 
> But, we do want to compile udevsend with klibc if it is used.
> udevd will be compiled while "make install" using libc,
> not nice but it works.

yeah, I will just copy the missing file.

-- 
USB is for mice, FireWire is for men!

sUse lINUX ag, n√úRNBERG


-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

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

end of thread, other threads:[~2004-02-08 16:09 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-01-25 20:03 [patch] udevd - cleanup and better timeout handling Kay Sievers
2004-01-26 18:22 ` Greg KH
2004-01-26 19:11 ` Kay Sievers
2004-01-26 19:28 ` Greg KH
2004-01-26 19:42 ` Kay Sievers
2004-01-26 22:26 ` Greg KH
2004-01-26 22:56 ` Kay Sievers
2004-01-27  6:56 ` Kay Sievers
2004-01-27 18:55 ` Greg KH
2004-01-27 19:08 ` Kay Sievers
2004-01-27 19:13 ` Greg KH
2004-01-28 21:47 ` Kay Sievers
2004-01-29  1:52 ` Kay Sievers
2004-01-29  1:56 ` Kay Sievers
2004-01-29 15:55 ` Kay Sievers
2004-01-31  2:42 ` Kay Sievers
2004-02-01  9:08 ` Greg KH
2004-02-01 18:16 ` Kay Sievers
2004-02-02  2:19 ` Kay Sievers
2004-02-02  8:21 ` Greg KH
2004-02-02 11:50 ` Kay Sievers
2004-02-02 18:45 ` Greg KH
2004-02-02 21:36 ` Kay Sievers
2004-02-03  1:26 ` Greg KH
2004-02-03  6:43 ` Ling, Xiaofeng
2004-02-03 20:12 ` Kay Sievers
2004-02-04  0:56 ` Greg KH
2004-02-08  9:43 ` Olaf Hering
2004-02-08 15:22 ` Kay Sievers
2004-02-08 15:40 ` Olaf Hering
2004-02-08 15:57 ` Kay Sievers
2004-02-08 16:09 ` Olaf Hering

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.