Skip to contentSkip to conversation

Task Ornaments

RFC New David Howells 1 participant 1 message Jan 26, 2001

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

RFC 1/1 Task Ornaments

PROPOSAL
========

I have written a patch (appended) that gives a task structure a list of arbitrary "ornaments". Any number of ornaments can then be added without increasing the size of the task_struct.

Each ornament has an operations table, much as do inodes and address spaces. These operations include a destructor and routines for destroying and duplicating ornaments under signal, exit, execve and fork/clone conditions.

For instance, the frame buffer drivers use a three fields in the task structure to gain notification of signals that are blocked from being delivered to a process:
- notifier
- notifier_data
- notifier_mask

Instead, these fields could be attached to an ornament which is only present when the FB driver is doing this. They would use the signal notification operation to perform this function.

In this way, the task_struct size could actually be _reduced_ by 4 bytes.

Functions are provided for traversing the list and calling the appropriate notification routine on each ornament. Multiple traversals can be in progress at once, and they can be recursive, and the list can be safely modified at the same time.

The implementation I've appended does work in userspace tests (as far as it is possible to test it there), though it has not been tried in the kernel as yet.

One optimisation that can be made is to make alloc_lock in the task_struct an rwlock_t instead of a spinlock_t. This means that the list can be searched simultaneously be several different processes.

REASON FOR IMPLEMENTATION
=========================

In the Win32 kernel module that I'm writing to help accelerate Wine, one of the things I want to do is to be able to store a Win32 handle map in a task structure (currently I attach it to an open fd).

There are a number of things my code needs to be able to do:

(1) Destroy the handle map upon exit, signal and potentially execve.

(2) Trim the handle map during execve.

(3) Duplicate/share the handle map of a process with a child process during forking/cloning.

(4) A process needs to be able to add objects to the handle map of another arbitrary process that also has a handle map.

(5) A process needs to be able to gain notification of the death of another arbitrary process.

The way I'm proposing to do this is by providing notifications from certain routines, such as do_fork().

There are a number of further considerations:

(1) A notification service routine can sleep (eg: on kmalloc).

(2) A service routine may modify the list (eg: remove itself).

(3) The list must be guarded against modifications during traversal without preventing modifications from happening.

Thanks for your consideration/comments/better ways of doing it, David

======================================================

fs/exec.c +1 -0
diff -uNr linux-2.4.1-pre10.orig/fs/exec.c linux-2.4.1-pre10/fs/exec.c
@@ -541,6 +541,7 @@
 	if (retval) goto mmap_failed;
 
 	/* This is the point of no return */
+	task_ornament_notify_execve(current);
 	release_old_signals(oldsig);
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
include/linux/sched.h +5 -4
diff -uNr linux-2.4.1-pre10.orig/include/linux/sched.h linux-2.4.1-pre10/include/linux/sched.h
@@ -394,7 +394,8 @@
    	u32 parent_exec_id;
    	u32 self_exec_id;
 /* Protection of (de-)allocation: mm, files, fs, tty */
-	spinlock_t alloc_lock;
+	rwlock_t alloc_lock;
+	struct list_head ornaments;
 };
 
 /*
@@ -474,7 +475,7 @@
     sig:		&init_signals,					\
     pending:		{ NULL, &tsk.pending.head, {{0}}},		\
     blocked:		{{0}},						\
-    alloc_lock:		SPIN_LOCK_UNLOCKED				\
+    alloc_lock:		RW_LOCK_UNLOCKED				\
 }
 
 
@@ -859,12 +860,12 @@
 
 static inline void task_lock(struct task_struct *p)
 {
-	spin_lock(&p->alloc_lock);
+	write_lock(&p->alloc_lock);
 }
 
 static inline void task_unlock(struct task_struct *p)
 {
-	spin_unlock(&p->alloc_lock);
+	write_unlock(&p->alloc_lock);
 }
 
 /* write full pathname into buffer and return start of pathname */
include/linux/taskornament.h +129 -0

129 lines not on this page · raw message

kernel/exit.c +3 -0
diff -uNr linux-2.4.1-pre10.orig/kernel/exit.c linux-2.4.1-pre10/kernel/exit.c
@@ -371,6 +371,9 @@
 	    && !capable(CAP_KILL))
 		current->exit_signal = SIGCHLD;
 
+	/* tell our ornaments we're dying */
+	task_ornament_notify_exit(current,current->exit_code);
+	exit_task_ornaments();
 
 	/*
 	 * This loop does two things:
kernel/fork.c +6 -1
diff -uNr linux-2.4.1-pre10.orig/kernel/fork.c linux-2.4.1-pre10/kernel/fork.c
@@ -612,7 +612,7 @@
 	p->p_cptr = NULL;
 	init_waitqueue_head(&p->wait_chldexit);
 	p->vfork_sem = NULL;
-	spin_lock_init(&p->alloc_lock);
+	rwlock_init(&p->alloc_lock);
 
 	p->sigpending = 0;
 	init_sigpending(&p->pending);
@@ -675,6 +675,11 @@
 	current->counter >>= 1;
 	if (!current->counter)
 		current->need_resched = 1;
+
+	/*
+	 * tell any ornaments to duplicate themselves
+	 */
+	task_ornament_notify_fork(current,p,clone_flags);
 
 	/*
 	 * Ok, add it to the run-queues and make it
kernel/signal.c +3 -0
diff -uNr linux-2.4.1-pre10.orig/kernel/signal.c linux-2.4.1-pre10/kernel/signal.c
@@ -242,6 +242,9 @@
 #endif
 
 	sig = next_signal(current, mask);
+
+	task_ornament_notify_signal(tsk,sig);
+
 	if (current->notifier) {
 		if (sigismember(current->notifier_mask, sig)) {
 			if (!(current->notifier)(current->notifier_data)) {
kernel/taskornament.c +330 -0

330 lines not on this page · raw message

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
Please read the FAQ at http://www.tux.org/lkml/