public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] pid_max hang again...
@ 2002-09-11  8:59 Hanumanthu. H
  2002-09-11 17:19 ` Andries Brouwer
  0 siblings, 1 reply; 18+ messages in thread
From: Hanumanthu. H @ 2002-09-11  8:59 UTC (permalink / raw)
  To: linux-kernel


>> I don't know what the problem is. The present scheme is very
>> efficient on the average (since the pid space is very large,
>> much larger than the number of processes, this scan is hardly
>> ever done)

> The scan itself i don't mind. It is the rescan that bothers me

And most of others too. One thing that strikes some minds
immediatly after looking at current pid allocation, is the need
for improvement. Well, even though the proposals are be clumsy,
in-efficient (really ?) we should not ignore the fact that this
is an area to improve. Ok, here is my final (more better) proposal
which fixes the atomicity problem addressed by ManFred.


Lets us have a structure to represent pid, session, pgrp and tgid.

struct idobject {
	struct idobject	*id_next;
	struct idobject *id_prev;
	int		value;
	atomic_t	users;
	task_t		*taskp;
};

Rather than linking task_structs in pid_hash table, we maintain
these ID objects in pidhash table. So, remove pidhash link ptrs
from task struct and put them in idobject structure. The members
represent:

id_next & id_prev : links to hash next & prev entries in pidhash
		    table

value		  : the value represented by this object

users		  : number of users for this object. This counts
		    the number of references for this object.

taskp		  : task that uses this object as PID


And each task_struct will have the following pointers:


	struct idobject *pidp;	   // ptr to pid object
	struct idobject *sessionp; // ptr to session object
	struct idobject *pgrpp;	   // ptr to pgrp object
	struct idobject *tgidp;    // ptr to thread grp object

(To avoid all changes at once, we can retain their non-ptr
 versions i.e session, pid, pgrp and tgid members of task_struct).

A task acquire's pid by calling set_pid() function, giving its
task_struct so that pid assignment would be atomic (i,e to address
the issue raised by Manfred). set_pid() allocates an idobject
structure, assigns a free pid and sets the objp->taskp to the
given task. Based on the pid, it hashes the idobject structure
into pidhash table. All this by holding lastpid_lock only, so that
pid assignments won't be duplicated.

Upon acquiring a pid, pidp's users member will be incremented by 1.
Likewise sessionp, pgrpp and tgidp users also will be incremented
whenever this task establishes relationship with them.

When a process is exiting, it decrements `users' members of
these objects and if they become zero, it un-hashes the object
based on its value.

This design allows two things:

1. Atomicity in object allocation

2. Efficiency in pid allocation, because reduction in
   search time and avoiding tasklist_lock.

If people does not bother in maintaining few more pointers,
we can achive an efficient way of tracking all members of
a session or process group.

Hmm...does this idea make any better sense ? If people have
any comments, please let me know..  If this is going to be
another clumsy, in-efficient idea, I will assure that I will
stop thinking about it :-)


Regards
Hanumanthu


^ permalink raw reply	[flat|nested] 18+ messages in thread
* Re: [PATCH] pid_max hang again...
@ 2002-09-07  9:06 Manfred Spraul
  2002-09-09 14:22 ` Hanumanthu. H
  0 siblings, 1 reply; 18+ messages in thread
From: Manfred Spraul @ 2002-09-07  9:06 UTC (permalink / raw)
  To: Hanumanthu. H; +Cc: linux-kernel

> As Manfred pointed out, pid allocation and inserting it into task
> list should be atomic. But going by the range of pids available
> in 2.5.33 (Linux made it 30-bits), it is unlikely that same pid
> will be given to two processes, since last_pid is protected by
> single lock. 
Right now there is quite a lot of code between get_pid and the insertion 
into the task list: copy mm, files, etc.

And just before the endless loop in get_pid(), there is only one pid 
left --> probability of getting the same pid again is high. If you fix 
the hang, you should fix the atomicity, too.

> If last_pid is within PID_MAX and max_pid_cross is set, this
> pid might have been given to another process. So, goto the
> corresponding hashlist and check for its existence. If no task
> with given pid found, then get_pid is free to return pid as the
> available pid.

Doesn't work: find_task_by_pid() only checks task->pid. But the result 
of get_pid mustn't be in use as a session or tgid value either

--
	Manfred


^ permalink raw reply	[flat|nested] 18+ messages in thread
* Re: [PATCH] pid_max hang again...
@ 2002-09-07  8:16 Hanumanthu. H
  0 siblings, 0 replies; 18+ messages in thread
From: Hanumanthu. H @ 2002-09-07  8:16 UTC (permalink / raw)
  To: linux-kernel; +Cc: torvalds

Hi,

The following patch tries to fix the max_pid hang problem. The
idea is to make use of find_task_by_pid(), rather than looping
over entire tasklist. We can make use of the fact that, the
maximum number of processes at any time does not exceed max value
of a 30-bit integer (last_pid).

As Manfred pointed out, pid allocation and inserting it into task
list should be atomic. But going by the range of pids available
in 2.5.33 (Linux made it 30-bits), it is unlikely that same pid
will be given to two processes, since last_pid is protected by
single lock. If a process gets a pid of x, all following processes
will get pids > x. So, another process getting pid x again means,
last_pid looped over it's maximum value and comes back to x while
the first process which got pid x is not yet inserted into the
list. This is definitely unlikely.


Given patch works as follows

get_pid starts by incrementing last_pid as usual. But when it
crosses PID_MAX, it sets a variable max_pid_cross to TRUE (1).
If last_pid is within PID_MAX and max_pid_cross is not set, we
are sure that we got a free pid, which is/was not yet allocated
to any process.

If last_pid is within PID_MAX and max_pid_cross is set, this
pid might have been given to another process. So, goto the
corresponding hashlist and check for its existence. If no task
with given pid found, then get_pid is free to return pid as the
available pid. If there is a process last_pid as its pid,
then increment last_pid, continue the looping in the respective
hashlist. get_pid() holds tasklist_lock before calling
find_task_by_pid() and releases it after find_task_by_pid()
returns. This ensures that any exiting processes will get
a chance to acquire the tasklist_lock and remove its entry
from tasklist. Since last_pid is protected by a single lock
we are sure that get_pid() will surely returns a free pid
without hang.

The patch applies to 2.5.33 kernel

Any comments/flames ? If nothing, please consider to apply.


~Hanumanthu
 Wipro Ltd.


diff -Nru linux-2.5.33/kernel/fork.c linux-2.5.33.1/kernel/fork.c

--- linux-2.5.33/kernel/fork.c	Sun Sep  1 03:34:49 2002
+++ linux-2.5.33.1/kernel/fork.c	Sat Sep  7 15:04:49 2002
@@ -76,7 +76,6 @@
 	}
 }

-/* Protects next_safe and last_pid. */
 void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
@@ -151,50 +150,34 @@
 	return tsk;
 }

+/* Protects next_safe and last_pid. */
 spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;

 static int get_pid(unsigned long flags)
 {
-	static int next_safe = PID_MAX;
-	struct task_struct *p;
+	static int  max_pid_cross;
 	int pid;

 	if (flags & CLONE_IDLETASK)
 		return 0;

 	spin_lock(&lastpid_lock);
-	if((++last_pid) & ~PID_MASK) {
+
+	if ((++last_pid) & ~PID_MASK) {
+		max_pid_cross = 1;
 		last_pid = 300;		/* Skip daemons etc. */
-		goto inside;
-	}
-	if(last_pid >= next_safe) {
-inside:
-		next_safe = PID_MAX;
-		read_lock(&tasklist_lock);
-	repeat:
-		for_each_task(p) {
-			if(p->pid == last_pid	||
-			   p->pgrp == last_pid	||
-			   p->tgid == last_pid	||
-			   p->session == last_pid) {
-				if(++last_pid >= next_safe) {
-					if(last_pid & ~PID_MASK)
-						last_pid = 300;
-					next_safe = PID_MAX;
-				}
-				goto repeat;
-			}
-			if(p->pid > last_pid && next_safe > p->pid)
-				next_safe = p->pid;
-			if(p->pgrp > last_pid && next_safe > p->pgrp)
-				next_safe = p->pgrp;
-			if(p->tgid > last_pid && next_safe > p->tgid)
-				next_safe = p->tgid;
-			if(p->session > last_pid && next_safe > p->session)
-				next_safe = p->session;
-		}
+	} else if(!max_pid_cross)
+		goto get_out;
+repeat:
+	read_lock(&tasklist_lock);
+	if (find_task_by_pid(last_pid)) {
 		read_unlock(&tasklist_lock);
+		if ((++last_pid) & ~PID_MASK)
+			last_pid = 300;
+		goto repeat;
 	}
+	read_unlock(&tasklist_lock);
+get_out:
 	pid = last_pid;
 	spin_unlock(&lastpid_lock);



^ permalink raw reply	[flat|nested] 18+ messages in thread
* Re: [PATCH] pid_max hang again...
@ 2002-09-06 21:06 Manfred Spraul
  0 siblings, 0 replies; 18+ messages in thread
From: Manfred Spraul @ 2002-09-06 21:06 UTC (permalink / raw)
  To: Paul Larson; +Cc: linux-kernel


Searching for a free pid value and inserting the thread into the task 
list should be atomic, otherwise the same pid value could be given to 2 
threads.

do_fork runs without the BLK, you might have to search for the pid 
within the write_lock_irq(&tasklist_lock) block.

--
	Manfred


^ permalink raw reply	[flat|nested] 18+ messages in thread
* Re: pid_max hang again...
@ 2002-09-06 15:39 Ingo Molnar
  2002-09-06 17:43 ` [PATCH] " Paul Larson
  0 siblings, 1 reply; 18+ messages in thread
From: Ingo Molnar @ 2002-09-06 15:39 UTC (permalink / raw)
  To: Paul Larson; +Cc: Linus Torvalds, lkml


On 6 Sep 2002, Paul Larson wrote:

> It looks like this change dropped us back to the same error all this was
> originally supposed to fix.  When you hit PID_MAX, get_pid() starts
> looping forever looking for a free pid and hangs.  I could probably make
> my original fix work on this very easily if you'd like.

yes please send a patch for this. Reintroduction of the looping bug was
unintended.

> I wonder though, would it be possible to do this in a more simple way by
> just throttling max_threads back to something more sane if it gets
> defaulted too high?  Since it gets checked before we even get to the
> get_pid call in copy_process().  That would keep the number of processes
> down to a sane level without the risk.

this is a good approach as well, but now pid_max can be adjusted runtime
so truncating max_threads as a side-effect looks a bit problematic. We
should rather fail the fork() cleanly.

	Ingo


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

end of thread, other threads:[~2002-09-13  5:33 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-09-11  8:59 [PATCH] pid_max hang again Hanumanthu. H
2002-09-11 17:19 ` Andries Brouwer
2002-09-11 20:23   ` jw schultz
2002-09-12  1:11   ` Rik van Riel
2002-09-12  1:54   ` Andrew Morton
2002-09-12 20:23     ` Andries Brouwer
2002-09-12 21:17       ` Rik van Riel
2002-09-12 21:21         ` yodaiken
2002-09-13  5:47       ` Hanumanthu. H
  -- strict thread matches above, loose matches on Subject: below --
2002-09-07  9:06 Manfred Spraul
2002-09-09 14:22 ` Hanumanthu. H
2002-09-09 15:07   ` Martin J. Bligh
2002-09-09 22:39     ` jw schultz
2002-09-10  9:54       ` Andries Brouwer
2002-09-10 19:29         ` jw schultz
2002-09-07  8:16 Hanumanthu. H
2002-09-06 21:06 Manfred Spraul
2002-09-06 15:39 Ingo Molnar
2002-09-06 17:43 ` [PATCH] " Paul Larson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox