Re: [patch] drivers: wait for threaded probes between initcall levels

Adam J. Richter
2006-10-28T23:53:19Z

On 2006-10-28 19:41:50, Linus Torvalds wrote:
>On Sat, 28 Oct 2006, Adam J. Richter wrote:
>
>> On Fri, 27 Oct 2006 13:42:44 -0700 (PDT), Linus Torvals wrote:
>> > static struct semaphore outstanding;
>> [...]
>> > static void allow_parallel(int n)
>> [...]
>> > static void wait_for_parallel(int n)
>> [...]
>> > static void execute_in_parallel(int (*fn)(void *), void *arg)
>>
>> This interface would have problems with nesting.
>
>You miss the point.
>
>They _wouldn't_ be nested.
>
>The "allow_parallel()" and "wait_for_parallel()" calls would be at some
>top-level situation (ie initcalls looping).
>
>Nobody else than the top level would _ever_ use them. Anything under that
>level would just say "I want to do this in parallel" - which is just a
>statement, and has no nesting issues in itself.

If only calls to execute_in_parallel nest, your original
implementation would always deadlock when the nesting depth exceeds
the allowed number of threads, and also potentially in some shallower
nesting depths given a very unlucky order of execution. In your
original message, you mentioned allowing the parallelism limit to be
set as low as 1.

One solution to this problem would be to have
execute_in_parallel execute the function directly when no threads are
available to do it, rather than blocking. The disadvantage is that,
if no thread is immediately available, the call to
execute_in_parallel would not return until the function that was
passed in finishes, even if more threads become available much sooner.

Here is what I am referring to, again completely untested:

static void execute_in_parallel(int (*fn)(void *), void *arg)
{
struct thread_exec arg = { .fn = fn, .arg = arg };

/* If no threads are available, call the function directly. */
if (down_trylock(&outstanding) != 0) {
fn(arg);
return;
}

arg.fn = fn;
arg.arg = arg;
init_completion(&arg.args_copied);

kernel_thread(do_in_parallel, &arg);

/* We need to wait until our "arg" is safe */
wait_for_completion(&arg.args_copied)
}

Adam Richter