Re: [PATCH for 2.5] preemptible kernel

From: Nigel Gamble (nigel@nrg.org)
Date: Thu Mar 29 2001 - 19:26:44 EST


On Tue, 20 Mar 2001, Nigel Gamble wrote:
> On Tue, 20 Mar 2001, Rusty Russell wrote:
> > Thoughts?
>
> Perhaps synchronize_kernel() could take the run_queue lock, mark all the
> tasks on it and count them. Any task marked when it calls schedule()
> voluntarily (but not if it is preempted) is unmarked and the count
> decremented. synchronize_kernel() continues until the count is zero.

Hi Rusty,

Here is an attempt at a possible version of synchronize_kernel() that
should work on a preemptible kernel. I haven't tested it yet.

static int sync_count = 0;
static struct task_struct *syncing_task = NULL;
static DECLARE_MUTEX(synchronize_kernel_mtx);

void
synchronize_kernel()
{
        struct list_head *tmp;
        struct task_struct *p;

        /* Guard against multiple calls to this function */
        down(&synchronize_kernel_mtx);

        /* Mark all tasks on the runqueue */
        spin_lock_irq(&runqueue_lock);
        list_for_each(tmp, &runqueue_head) {
                p = list_entry(tmp, struct task_struct, run_list);
                if (p == current)
                        continue;
                if (p->state == TASK_RUNNING ||
                                (p->state == (TASK_RUNNING|TASK_PREEMPTED))) {
                        p->flags |= PF_SYNCING;
                        sync_count++;
                }
        }
        if (sync_count == 0)
                goto out;

        syncing_task = current;
        spin_unlock_irq(&runqueue_lock);

        /*
         * Cause a schedule on every CPU, as for a non-preemptible
         * kernel
         */

        /* Save current state */
        cpus_allowed = current->cpus_allowed;
        policy = current->policy;
        rt_priority = current->rt_priority;

        /* Create an unreal time task. */
        current->policy = SCHED_FIFO;
        current->rt_priority = 1001 + sys_sched_get_priority_max(SCHED_FIFO);

        /* Make us schedulable on all CPUs. */
        current->cpus_allowed = (1UL<<smp_num_cpus)-1;

        /* Eliminate current cpu, reschedule */
        while ((current->cpus_allowed &= ~(1 << smp_processor_id())) != 0)
                schedule();

        /* Back to normal. */
        current->cpus_allowed = cpus_allowed;
        current->policy = policy;
        current->rt_priority = rt_priority;

        /*
         * Wait, if necessary, until all preempted tasks
         * have reached a sync point.
         */

        spin_lock_irq(&runqueue_lock);
        for (;;) {
                set_current_state(TASK_UNINTERRUPTIBLE);
                if (sync_count == 0)
                        break;
                spin_unlock_irq(&runqueue_lock);
                schedule();
                spin_lock_irq(&runqueue_lock);
        }
        current->state = TASK_RUNNING;
        syncing_task = NULL;
out:
        spin_unlock_irq(&runqueue_lock);

        up(&synchronize_kernel_mtx);
}

And add this code to the beginning of schedule(), just after the
runqueue_lock is taken (the flags field is probably not be the right
place to put the synchronize mark; and the test should be optimized for
the fast path in the same way as the other tests in schedule(), but you
get the idea):

        if ((prev->flags & PF_SYNCING) && !(prev->state & TASK_PREEMPTED)) {
                prev->flags &= ~PF_SYNCING;
                if (--sync_count == 0) {
                        syncing_task->state = TASK_RUNNING;
                        if (!task_on_runqueue(syncing_task))
                                add_to_runqueue(syncing_task);
                        syncing_task = NULL;
                }

        }

Nigel Gamble nigel@nrg.org
Mountain View, CA, USA. http://www.nrg.org/

MontaVista Software nigel@mvista.com

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



This archive was generated by hypermail 2b29 : Sat Mar 31 2001 - 21:00:22 EST