From ea53c912f8a86a8567697115b6a0d8152beee5c8 Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Sun, 4 Mar 2012 19:39:40 -0500 Subject: Prepare k-FMLP for integration with Linux 3.0 Also added k-fmlp support to CEDF. --- litmus/sched_cedf.c | 603 +++++++++++++++++++++++++++++++++++++++++++++++-- litmus/sched_gsn_edf.c | 36 +-- 2 files changed, 590 insertions(+), 49 deletions(-) diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index 73fe1c442a0d..5e977dd2fef0 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -45,7 +46,6 @@ /* to configure the cluster size */ #include -#include /* Reference configuration variable. Determines which cache level is used to * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that @@ -95,7 +95,7 @@ typedef struct clusterdomain { struct bheap_node *heap_node; struct bheap cpu_heap; /* lock for this cluster */ -#define lock domain.ready_lock +#define cedf_lock domain.ready_lock } cedf_domain_t; /* a cedf_domain per cluster; allocation is done at init/activation time */ @@ -292,12 +292,12 @@ static void cedf_release_jobs(rt_domain_t* rt, struct bheap* tasks) cedf_domain_t* cluster = container_of(rt, cedf_domain_t, domain); unsigned long flags; - raw_spin_lock_irqsave(&cluster->lock, flags); + raw_spin_lock_irqsave(&cluster->cedf_lock, flags); __merge_ready(&cluster->domain, tasks); check_for_preemptions(cluster); - raw_spin_unlock_irqrestore(&cluster->lock, flags); + raw_spin_unlock_irqrestore(&cluster->cedf_lock, flags); } /* caller holds cedf_lock */ @@ -378,7 +378,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) int out_of_time, sleep, preempt, np, exists, blocks; struct task_struct* next = NULL; - raw_spin_lock(&cluster->lock); + raw_spin_lock(&cluster->cedf_lock); clear_will_schedule(); /* sanity checking */ @@ -462,7 +462,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) next = prev; sched_state_task_picked(); - raw_spin_unlock(&cluster->lock); + raw_spin_unlock(&cluster->cedf_lock); #ifdef WANT_ALL_SCHED_EVENTS TRACE("cedf_lock released, next=0x%p\n", next); @@ -504,7 +504,7 @@ static void cedf_task_new(struct task_struct * t, int on_rq, int running) /* the cluster doesn't change even if t is running */ cluster = task_cpu_cluster(t); - raw_spin_lock_irqsave(&cluster->domain.ready_lock, flags); + raw_spin_lock_irqsave(&cluster->cedf_lock, flags); /* setup job params */ release_at(t, litmus_clock()); @@ -521,7 +521,7 @@ static void cedf_task_new(struct task_struct * t, int on_rq, int running) t->rt_param.linked_on = NO_CPU; cedf_job_arrival(t); - raw_spin_unlock_irqrestore(&(cluster->domain.ready_lock), flags); + raw_spin_unlock_irqrestore(&(cluster->cedf_lock), flags); } static void cedf_task_wake_up(struct task_struct *task) @@ -534,7 +534,7 @@ static void cedf_task_wake_up(struct task_struct *task) cluster = task_cpu_cluster(task); - raw_spin_lock_irqsave(&cluster->lock, flags); + raw_spin_lock_irqsave(&cluster->cedf_lock, flags); /* We need to take suspensions because of semaphores into * account! If a job resumes after being suspended due to acquiring * a semaphore, it should never be treated as a new job release. @@ -557,7 +557,7 @@ static void cedf_task_wake_up(struct task_struct *task) } } cedf_job_arrival(task); - raw_spin_unlock_irqrestore(&cluster->lock, flags); + raw_spin_unlock_irqrestore(&cluster->cedf_lock, flags); } static void cedf_task_block(struct task_struct *t) @@ -570,9 +570,9 @@ static void cedf_task_block(struct task_struct *t) cluster = task_cpu_cluster(t); /* unlink if necessary */ - raw_spin_lock_irqsave(&cluster->lock, flags); + raw_spin_lock_irqsave(&cluster->cedf_lock, flags); unlink(t); - raw_spin_unlock_irqrestore(&cluster->lock, flags); + raw_spin_unlock_irqrestore(&cluster->cedf_lock, flags); BUG_ON(!is_realtime(t)); } @@ -584,7 +584,7 @@ static void cedf_task_exit(struct task_struct * t) cedf_domain_t *cluster = task_cpu_cluster(t); /* unlink if necessary */ - raw_spin_lock_irqsave(&cluster->lock, flags); + raw_spin_lock_irqsave(&cluster->cedf_lock, flags); unlink(t); if (tsk_rt(t)->scheduled_on != NO_CPU) { cpu_entry_t *cpu; @@ -592,7 +592,7 @@ static void cedf_task_exit(struct task_struct * t) cpu->scheduled = NULL; tsk_rt(t)->scheduled_on = NO_CPU; } - raw_spin_unlock_irqrestore(&cluster->lock, flags); + raw_spin_unlock_irqrestore(&cluster->cedf_lock, flags); BUG_ON(!is_realtime(t)); TRACE_TASK(t, "RIP\n"); @@ -603,6 +603,578 @@ static long cedf_admit_task(struct task_struct* tsk) return task_cpu(tsk) == tsk->rt_param.task_params.cpu ? 0 : -EINVAL; } + + + + + + + + + + + + +#ifdef CONFIG_LITMUS_LOCKING + +#include + + +static void __set_priority_inheritance(struct task_struct* t, struct task_struct* prio_inh) +{ + int linked_on; + int check_preempt = 0; + + cedf_domain_t* cluster = task_cpu_cluster(t); + + if(prio_inh != NULL) + TRACE_TASK(t, "inherits priority from %s/%d\n", prio_inh->comm, prio_inh->pid); + else + TRACE_TASK(t, "inherits priority from %p\n", prio_inh); + + //sched_trace_eff_prio_change(t, prio_inh); + + tsk_rt(t)->inh_task = prio_inh; + + linked_on = tsk_rt(t)->linked_on; + + /* If it is scheduled, then we need to reorder the CPU heap. */ + if (linked_on != NO_CPU) { + TRACE_TASK(t, "%s: linked on %d\n", + __FUNCTION__, linked_on); + /* Holder is scheduled; need to re-order CPUs. + * We can't use heap_decrease() here since + * the cpu_heap is ordered in reverse direction, so + * it is actually an increase. */ + bheap_delete(cpu_lower_prio, &cluster->cpu_heap, + per_cpu(cedf_cpu_entries, linked_on).hn); + bheap_insert(cpu_lower_prio, &cluster->cpu_heap, + per_cpu(cedf_cpu_entries, linked_on).hn); + } else { + /* holder may be queued: first stop queue changes */ + raw_spin_lock(&cluster->domain.release_lock); + if (is_queued(t)) { + TRACE_TASK(t, "%s: is queued\n", __FUNCTION__); + + /* We need to update the position of holder in some + * heap. Note that this could be a release heap if we + * budget enforcement is used and this job overran. */ + check_preempt = !bheap_decrease(edf_ready_order, tsk_rt(t)->heap_node); + + } else { + /* Nothing to do: if it is not queued and not linked + * then it is either sleeping or currently being moved + * by other code (e.g., a timer interrupt handler) that + * will use the correct priority when enqueuing the + * task. */ + TRACE_TASK(t, "%s: is NOT queued => Done.\n", __FUNCTION__); + } + raw_spin_unlock(&cluster->domain.release_lock); + + /* If holder was enqueued in a release heap, then the following + * preemption check is pointless, but we can't easily detect + * that case. If you want to fix this, then consider that + * simply adding a state flag requires O(n) time to update when + * releasing n tasks, which conflicts with the goal to have + * O(log n) merges. */ + if (check_preempt) { + /* heap_decrease() hit the top level of the heap: make + * sure preemption checks get the right task, not the + * potentially stale cache. */ + bheap_uncache_min(edf_ready_order, &cluster->domain.ready_queue); + check_for_preemptions(cluster); + } + } +} + +/* called with IRQs off */ +static void set_priority_inheritance(struct task_struct* t, struct task_struct* prio_inh) +{ + cedf_domain_t* cluster = task_cpu_cluster(t); + + raw_spin_lock(&cluster->cedf_lock); + + __set_priority_inheritance(t, prio_inh); + + raw_spin_unlock(&cluster->cedf_lock); +} + + +/* called with IRQs off */ +static void __clear_priority_inheritance(struct task_struct* t) +{ + TRACE_TASK(t, "priority restored\n"); + + if(tsk_rt(t)->scheduled_on != NO_CPU) + { + //sched_trace_eff_prio_change(t, NULL); + + tsk_rt(t)->inh_task = NULL; + + /* Check if rescheduling is necessary. We can't use heap_decrease() + * since the priority was effectively lowered. */ + unlink(t); + cedf_job_arrival(t); + } + else + { + __set_priority_inheritance(t, NULL); + } +} + +/* called with IRQs off */ +static void clear_priority_inheritance(struct task_struct* t) +{ + cedf_domain_t* cluster = task_cpu_cluster(t); + + raw_spin_lock(&cluster->cedf_lock); + __clear_priority_inheritance(t); + raw_spin_unlock(&cluster->cedf_lock); +} + + + +/* ******************** KFMLP support ********************** */ + +/* struct for semaphore with priority inheritance */ +struct kfmlp_queue +{ + wait_queue_head_t wait; + struct task_struct* owner; + struct task_struct* hp_waiter; + int count; /* number of waiters + holder */ +}; + +struct kfmlp_semaphore +{ + struct litmus_lock litmus_lock; + + spinlock_t lock; + + int num_resources; /* aka k */ + struct kfmlp_queue *queues; /* array */ + struct kfmlp_queue *shortest_queue; /* pointer to shortest queue */ +}; + +static inline struct kfmlp_semaphore* kfmlp_from_lock(struct litmus_lock* lock) +{ + return container_of(lock, struct kfmlp_semaphore, litmus_lock); +} + +static inline int kfmlp_get_idx(struct kfmlp_semaphore* sem, + struct kfmlp_queue* queue) +{ + return (queue - &sem->queues[0]); +} + +static inline struct kfmlp_queue* kfmlp_get_queue(struct kfmlp_semaphore* sem, + struct task_struct* holder) +{ + int i; + for(i = 0; i < sem->num_resources; ++i) + if(sem->queues[i].owner == holder) + return(&sem->queues[i]); + return(NULL); +} + +/* caller is responsible for locking */ +static struct task_struct* kfmlp_find_hp_waiter(struct kfmlp_queue *kqueue, + struct task_struct *skip) +{ + struct list_head *pos; + struct task_struct *queued, *found = NULL; + + list_for_each(pos, &kqueue->wait.task_list) { + queued = (struct task_struct*) list_entry(pos, wait_queue_t, + task_list)->private; + + /* Compare task prios, find high prio task. */ + if (queued != skip && edf_higher_prio(queued, found)) + found = queued; + } + return found; +} + +static inline struct kfmlp_queue* kfmlp_find_shortest( + struct kfmlp_semaphore* sem, + struct kfmlp_queue* search_start) +{ + // we start our search at search_start instead of at the beginning of the + // queue list to load-balance across all resources. + struct kfmlp_queue* step = search_start; + struct kfmlp_queue* shortest = sem->shortest_queue; + + do + { + step = (step+1 != &sem->queues[sem->num_resources]) ? + step+1 : &sem->queues[0]; + if(step->count < shortest->count) + { + shortest = step; + if(step->count == 0) + break; /* can't get any shorter */ + } + }while(step != search_start); + + return(shortest); +} + +static struct task_struct* kfmlp_remove_hp_waiter(struct kfmlp_semaphore* sem) +{ + /* must hold sem->lock */ + + struct kfmlp_queue *my_queue = NULL; + struct task_struct *max_hp = NULL; + + + struct list_head *pos; + struct task_struct *queued; + int i; + + for(i = 0; i < sem->num_resources; ++i) + { + if( (sem->queues[i].count > 1) && + ((my_queue == NULL) || + (edf_higher_prio(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) + { + my_queue = &sem->queues[i]; + } + } + + if(my_queue) + { + cedf_domain_t* cluster; + + max_hp = my_queue->hp_waiter; + BUG_ON(!max_hp); + + TRACE_CUR("queue %d: stealing %s/%d from queue %d\n", + kfmlp_get_idx(sem, my_queue), + max_hp->comm, max_hp->pid, + kfmlp_get_idx(sem, my_queue)); + + my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, max_hp); + + cluster = task_cpu_cluster(max_hp); + + raw_spin_lock(&cluster->cedf_lock); + + if(tsk_rt(my_queue->owner)->inh_task == max_hp) + { + __clear_priority_inheritance(my_queue->owner); + if(my_queue->hp_waiter != NULL) + { + __set_priority_inheritance(my_queue->owner, my_queue->hp_waiter); + } + } + raw_spin_unlock(&cluster->cedf_lock); + + list_for_each(pos, &my_queue->wait.task_list) + { + queued = (struct task_struct*) list_entry(pos, wait_queue_t, + task_list)->private; + /* Compare task prios, find high prio task. */ + if (queued == max_hp) + { + __remove_wait_queue(&my_queue->wait, + list_entry(pos, wait_queue_t, task_list)); + break; + } + } + --(my_queue->count); + } + + return(max_hp); +} + +int cedf_kfmlp_lock(struct litmus_lock* l) +{ + struct task_struct* t = current; + struct kfmlp_semaphore *sem = kfmlp_from_lock(l); + struct kfmlp_queue* my_queue; + wait_queue_t wait; + unsigned long flags; + + if (!is_realtime(t)) + return -EPERM; + + spin_lock_irqsave(&sem->lock, flags); + + my_queue = sem->shortest_queue; + + if (my_queue->owner) { + /* resource is not free => must suspend and wait */ + TRACE_CUR("queue %d: Resource is not free => must suspend and wait.\n", + kfmlp_get_idx(sem, my_queue)); + + init_waitqueue_entry(&wait, t); + + /* FIXME: interruptible would be nice some day */ + set_task_state(t, TASK_UNINTERRUPTIBLE); + + __add_wait_queue_tail_exclusive(&my_queue->wait, &wait); + + /* check if we need to activate priority inheritance */ + if (edf_higher_prio(t, my_queue->hp_waiter)) + { + my_queue->hp_waiter = t; + if (edf_higher_prio(t, my_queue->owner)) + { + set_priority_inheritance(my_queue->owner, my_queue->hp_waiter); + } + } + + ++(my_queue->count); + sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); + + /* release lock before sleeping */ + spin_unlock_irqrestore(&sem->lock, flags); + + /* We depend on the FIFO order. Thus, we don't need to recheck + * when we wake up; we are guaranteed to have the lock since + * there is only one wake up per release (or steal). + */ + schedule(); + + + if(my_queue->owner == t) + { + TRACE_CUR("queue %d: acquired through waiting\n", + kfmlp_get_idx(sem, my_queue)); + } + else + { + /* this case may happen if our wait entry was stolen + between queues. record where we went.*/ + my_queue = kfmlp_get_queue(sem, t); + BUG_ON(!my_queue); + TRACE_CUR("queue %d: acquired through stealing\n", + kfmlp_get_idx(sem, my_queue)); + } + } + else + { + TRACE_CUR("queue %d: acquired immediately\n", + kfmlp_get_idx(sem, my_queue)); + + my_queue->owner = t; + + ++(my_queue->count); + sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); + + spin_unlock_irqrestore(&sem->lock, flags); + } + + return kfmlp_get_idx(sem, my_queue); +} + +int cedf_kfmlp_unlock(struct litmus_lock* l) +{ + struct task_struct *t = current, *next; + struct kfmlp_semaphore *sem = kfmlp_from_lock(l); + struct kfmlp_queue *my_queue; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&sem->lock, flags); + + my_queue = kfmlp_get_queue(sem, t); + + if (!my_queue) { + err = -EINVAL; + goto out; + } + + /* check if there are jobs waiting for this resource */ + next = __waitqueue_remove_first(&my_queue->wait); + if (next) { + /* next becomes the resouce holder */ + my_queue->owner = next; + + --(my_queue->count); + if(my_queue->count < sem->shortest_queue->count) + { + sem->shortest_queue = my_queue; + } + + TRACE_CUR("queue %d: lock ownership passed to %s/%d\n", + kfmlp_get_idx(sem, my_queue), next->comm, next->pid); + + /* determine new hp_waiter if necessary */ + if (next == my_queue->hp_waiter) { + TRACE_TASK(next, "was highest-prio waiter\n"); + /* next has the highest priority --- it doesn't need to + * inherit. However, we need to make sure that the + * next-highest priority in the queue is reflected in + * hp_waiter. */ + my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, next); + if (my_queue->hp_waiter) + TRACE_TASK(my_queue->hp_waiter, "queue %d: is new highest-prio waiter\n", kfmlp_get_idx(sem, my_queue)); + else + TRACE("queue %d: no further waiters\n", kfmlp_get_idx(sem, my_queue)); + } else { + /* Well, if next is not the highest-priority waiter, + * then it ought to inherit the highest-priority + * waiter's priority. */ + set_priority_inheritance(next, my_queue->hp_waiter); + } + + /* wake up next */ + wake_up_process(next); + } + else + { + TRACE_CUR("queue %d: looking to steal someone...\n", kfmlp_get_idx(sem, my_queue)); + + next = kfmlp_remove_hp_waiter(sem); /* returns NULL if nothing to steal */ + + my_queue->owner = next; + + if(next) + { + TRACE_CUR("queue %d: lock ownership passed to %s/%d (which was stolen)\n", + kfmlp_get_idx(sem, my_queue), + next->comm, next->pid); + + /* wake up next */ + wake_up_process(next); + } + else + { + TRACE_CUR("queue %d: no one to steal.\n", kfmlp_get_idx(sem, my_queue)); + + --(my_queue->count); + if(my_queue->count < sem->shortest_queue->count) + { + sem->shortest_queue = my_queue; + } + } + } + + /* we lose the benefit of priority inheritance (if any) */ + if (tsk_rt(t)->inh_task) + clear_priority_inheritance(t); + +out: + spin_unlock_irqrestore(&sem->lock, flags); + + return err; +} + +int cedf_kfmlp_close(struct litmus_lock* l) +{ + struct task_struct *t = current; + struct kfmlp_semaphore *sem = kfmlp_from_lock(l); + struct kfmlp_queue *my_queue; + unsigned long flags; + + int owner; + + spin_lock_irqsave(&sem->lock, flags); + + my_queue = kfmlp_get_queue(sem, t); + owner = (my_queue) ? (my_queue->owner == t) : 0; + + spin_unlock_irqrestore(&sem->lock, flags); + + if (owner) + cedf_kfmlp_unlock(l); + + return 0; +} + +void cedf_kfmlp_free(struct litmus_lock* l) +{ + struct kfmlp_semaphore *sem = kfmlp_from_lock(l); + kfree(sem->queues); + kfree(sem); +} + +static struct litmus_lock_ops cedf_kfmlp_lock_ops = { + .close = cedf_kfmlp_close, + .lock = cedf_kfmlp_lock, + .unlock = cedf_kfmlp_unlock, + .deallocate = cedf_kfmlp_free, +}; + +static struct litmus_lock* cedf_new_kfmlp(void* __user arg, int* ret_code) +{ + struct kfmlp_semaphore* sem; + int num_resources = 0; + int i; + + if(!access_ok(VERIFY_READ, arg, sizeof(num_resources))) + { + *ret_code = -EINVAL; + return(NULL); + } + if(__copy_from_user(&num_resources, arg, sizeof(num_resources))) + { + *ret_code = -EINVAL; + return(NULL); + } + if(num_resources < 1) + { + *ret_code = -EINVAL; + return(NULL); + } + + sem = kmalloc(sizeof(*sem), GFP_KERNEL); + if(!sem) + { + *ret_code = -ENOMEM; + return NULL; + } + + sem->queues = kmalloc(sizeof(struct kfmlp_queue)*num_resources, GFP_KERNEL); + if(!sem->queues) + { + kfree(sem); + *ret_code = -ENOMEM; + return NULL; + } + + sem->litmus_lock.ops = &cedf_kfmlp_lock_ops; + spin_lock_init(&sem->lock); + sem->num_resources = num_resources; + + for(i = 0; i < num_resources; ++i) + { + sem->queues[i].owner = NULL; + sem->queues[i].hp_waiter = NULL; + init_waitqueue_head(&sem->queues[i].wait); + sem->queues[i].count = 0; + } + + sem->shortest_queue = &sem->queues[0]; + + *ret_code = 0; + return &sem->litmus_lock; +} + + +/* **** lock constructor **** */ + +static long cedf_allocate_lock(struct litmus_lock **lock, int type, + void* __user arg) +{ + int err = -ENXIO; + + /* C-EDF currently only supports the FMLP for global resources + WITHIN a given cluster. DO NOT USE CROSS-CLUSTER! */ + switch (type) { + case KFMLP_SEM: + *lock = cedf_new_kfmlp(arg, &err); + break; + }; + + return err; +} + +#endif // CONFIG_LITMUS_LOCKING + + + /* total number of cluster */ static int num_clusters; /* we do not support cluster of different sizes */ @@ -765,6 +1337,9 @@ static struct sched_plugin cedf_plugin __cacheline_aligned_in_smp = { .task_block = cedf_task_block, .admit_task = cedf_admit_task, .activate_plugin = cedf_activate_plugin, +#ifdef CONFIG_LITMUS_LOCKING + .allocate_lock = cedf_allocate_lock, +#endif }; static struct proc_dir_entry *cluster_file = NULL, *cedf_dir = NULL; diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index bf8d989f1c4a..b87524cf1802 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c @@ -935,7 +935,6 @@ struct kfmlp_semaphore spinlock_t lock; int num_resources; /* aka k */ - struct kfmlp_queue *queues; /* array */ struct kfmlp_queue *shortest_queue; /* pointer to shortest queue */ }; @@ -992,6 +991,7 @@ static inline struct kfmlp_queue* kfmlp_find_shortest( { step = (step+1 != &sem->queues[sem->num_resources]) ? step+1 : &sem->queues[0]; + if(step->count < shortest->count) { shortest = step; @@ -1038,31 +1038,8 @@ struct task_struct* kfmlp_remove_hp_waiter(struct kfmlp_semaphore* sem) my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, max_hp); - /* - if(my_queue->hp_waiter) - TRACE_CUR("queue %d: new hp_waiter is %s/%d\n", - kfmlp_get_idx(sem, my_queue), - my_queue->hp_waiter->comm, - my_queue->hp_waiter->pid); - else - TRACE_CUR("queue %d: new hp_waiter is %p\n", - kfmlp_get_idx(sem, my_queue), NULL); - */ - raw_spin_lock(&gsnedf_lock); - /* - if(my_queue->owner) - TRACE_CUR("queue %d: owner is %s/%d\n", - kfmlp_get_idx(sem, my_queue), - my_queue->owner->comm, - my_queue->owner->pid); - else - TRACE_CUR("queue %d: owner is %p\n", - kfmlp_get_idx(sem, my_queue), - NULL); - */ - if(tsk_rt(my_queue->owner)->inh_task == max_hp) { __clear_priority_inheritance(my_queue->owner); @@ -1080,10 +1057,6 @@ struct task_struct* kfmlp_remove_hp_waiter(struct kfmlp_semaphore* sem) /* Compare task prios, find high prio task. */ if (queued == max_hp) { - /* - TRACE_CUR("queue %d: found entry in wait queue. REMOVING!\n", - kfmlp_get_idx(sem, my_queue)); - */ __remove_wait_queue(&my_queue->wait, list_entry(pos, wait_queue_t, task_list)); break; @@ -1240,13 +1213,6 @@ int gsnedf_kfmlp_unlock(struct litmus_lock* l) next = kfmlp_remove_hp_waiter(sem); /* returns NULL if nothing to steal */ - /* - if(next) - TRACE_CUR("queue %d: ASSIGNING %s/%d as owner - steal\n", - kfmlp_get_idx(sem, my_queue), - next->comm, next->pid); - */ - my_queue->owner = next; if(next) -- cgit v1.2.2