697 lines · 17.3 KB · C
RawDownload
 * * schedule_on_each_cpu() is very slow. */int schedule_on_each_cpu(void (*func)(void *info), void *info){	int cpu;	struct work_struct *works; 	works = alloc_percpu(struct work_struct);	if (!works)		return -ENOMEM; 	mutex_lock(&workqueue_mutex);	for_each_online_cpu(cpu) {		INIT_WORK(per_cpu_ptr(works, cpu), func, info);		__queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),				per_cpu_ptr(works, cpu));	}	mutex_unlock(&workqueue_mutex);	flush_workqueue(keventd_wq);	free_percpu(works);	return 0;} void flush_scheduled_work(void){	flush_workqueue(keventd_wq);}EXPORT_SYMBOL(flush_scheduled_work); /** * cancel_rearming_delayed_workqueue - reliably kill off a delayed *			work whose handler rearms the delayed work. * @wq:   the controlling workqueue structure * @work: the delayed work struct */void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,				       struct work_struct *work){	while (!cancel_delayed_work(work))		flush_workqueue(wq);}EXPORT_SYMBOL(cancel_rearming_delayed_workqueue); /** * cancel_rearming_delayed_work - reliably kill off a delayed keventd *			work whose handler rearms the delayed work. * @work: the delayed work struct */void cancel_rearming_delayed_work(struct work_struct *work){	cancel_rearming_delayed_workqueue(keventd_wq, work);}EXPORT_SYMBOL(cancel_rearming_delayed_work); /** * execute_in_process_context - reliably execute the routine with user context * @fn:		the function to execute * @data:	data to pass to the function * @ew:		guaranteed storage for the execute work structure (must *		be available when the work executes) * * Executes the function immediately if process context is available, * otherwise schedules the function for delayed execution. * * Returns:	0 - function was executed *		1 - function was scheduled for execution */int execute_in_process_context(void (*fn)(void *data), void *data,			       struct execute_work *ew){	if (!in_interrupt()) {		fn(data);		return 0;	} 	INIT_WORK(&ew->work, fn, data);	schedule_work(&ew->work); 	return 1;}EXPORT_SYMBOL_GPL(execute_in_process_context); int keventd_up(void){	return keventd_wq != NULL;} int current_is_keventd(void){	struct cpu_workqueue_struct *cwq;	int cpu = smp_processor_id();	/* preempt-safe: keventd is per-cpu */	int ret = 0; 	BUG_ON(!keventd_wq); 	cwq = per_cpu_ptr(keventd_wq->cpu_wq, cpu);	if (current == cwq->thread)		ret = 1; 	return ret; } #ifdef CONFIG_HOTPLUG_CPU/* Take the work from this (downed) CPU. */static void take_over_work(struct workqueue_struct *wq, unsigned int cpu){	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);	struct list_head list;	struct work_struct *work; 	spin_lock_irq(&cwq->lock);	list_replace_init(&cwq->worklist, &list); 	while (!list_empty(&list)) {		printk("Taking work for %s\n", wq->name);		work = list_entry(list.next,struct work_struct,entry);		list_del(&work->entry);		__queue_work(per_cpu_ptr(wq->cpu_wq, smp_processor_id()), work);	}	spin_unlock_irq(&cwq->lock);} /* We're holding the cpucontrol mutex here */static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,				  unsigned long action,				  void *hcpu){	unsigned int hotcpu = (unsigned long)hcpu;	struct workqueue_struct *wq; 	switch (action) {	case CPU_UP_PREPARE:		mutex_lock(&workqueue_mutex);		/* Create a new workqueue thread for it. */		list_for_each_entry(wq, &workqueues, list) {			if (!create_workqueue_thread(wq, hotcpu)) {				printk("workqueue for %i failed\n", hotcpu);				return NOTIFY_BAD;			}		}		break; 	case CPU_ONLINE:		/* Kick off worker threads. */		list_for_each_entry(wq, &workqueues, list) {			struct cpu_workqueue_struct *cwq; 			cwq = per_cpu_ptr(wq->cpu_wq, hotcpu);			kthread_bind(cwq->thread, hotcpu);			wake_up_process(cwq->thread);		}		mutex_unlock(&workqueue_mutex);		break; 	case CPU_UP_CANCELED:		list_for_each_entry(wq, &workqueues, list) {			if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)				continue;			/* Unbind so it can run. */			kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,				     any_online_cpu(cpu_online_map));			cleanup_workqueue_thread(wq, hotcpu);		}		mutex_unlock(&workqueue_mutex);		break; 	case CPU_DOWN_PREPARE:		mutex_lock(&workqueue_mutex);		break; 	case CPU_DOWN_FAILED:		mutex_unlock(&workqueue_mutex);		break; 	case CPU_DEAD:		list_for_each_entry(wq, &workqueues, list)			cleanup_workqueue_thread(wq, hotcpu);		list_for_each_entry(wq, &workqueues, list)			take_over_work(wq, hotcpu);		mutex_unlock(&workqueue_mutex);		break;	} 	return NOTIFY_OK;}#endif void init_workqueues(void){	singlethread_cpu = first_cpu(cpu_possible_map);	hotcpu_notifier(workqueue_cpu_callback, 0);	keventd_wq = create_workqueue("events");	BUG_ON(!keventd_wq);} 

Lines 501–697 of 697. Previous lines