From patchwork Wed Sep 15 05:16:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 181762 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8F5Gxw6011831 for ; Wed, 15 Sep 2010 05:17:00 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752578Ab0IOFQ6 (ORCPT ); Wed, 15 Sep 2010 01:16:58 -0400 Received: from mail-pv0-f174.google.com ([74.125.83.174]:42787 "EHLO mail-pv0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752305Ab0IOFQ6 (ORCPT ); Wed, 15 Sep 2010 01:16:58 -0400 Received: by pvg2 with SMTP id 2so2618261pvg.19 for ; Tue, 14 Sep 2010 22:16:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:date:from:to:cc:subject :message-id:mime-version:content-type:content-disposition:user-agent; bh=Ucz5RVCt4G/J9nnOAli/urNoJJVVMKojRiKlagSqX6M=; b=XX8GZKnA3Jx7GBw1HHeyGd2gZtwd0cjtWySJvqgKi2pMzuJH2h6e2mlicaiXgHUAOr eusxl8dHV8tbcMneIwYorbD8Ho/V7X2APOcltNop7wWwTc+q6wr6GNeDu4uhapRqcMih Bzj0ck2EUNsmCZuIWyOxfH9gT5tBQiT2mOJHQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:mime-version:content-type :content-disposition:user-agent; b=xEbF1opUwy6X6Dp7FGt5lbuDhwaduqzeYFbVgL+lllAIFJ8HRtF/xn05V1poSdTiqh v4FrwYvj5TfoN0XdmNjDIH5xY2NpReMhdmzKSOJYkL+Ejb+yYFdEJ2ID4Ub7V398inXm n2yjF0CXJHJvPQPyTDKDHExfjt/B1ICdxuMKA= Received: by 10.142.148.9 with SMTP id v9mr983353wfd.96.1284527817837; Tue, 14 Sep 2010 22:16:57 -0700 (PDT) Received: from mailhub.coreip.homeip.net (c-24-6-153-206.hsd1.ca.comcast.net [24.6.153.206]) by mx.google.com with ESMTPS id d38sm1639112wam.8.2010.09.14.22.16.55 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 14 Sep 2010 22:16:56 -0700 (PDT) Date: Tue, 14 Sep 2010 22:16:52 -0700 From: Dmitry Torokhov To: Linux Input Cc: Tejun Heo Subject: [RFC] Input: serio - convert to use workqueue instead of a thread Message-ID: <20100915051652.GA22219@core.coreip.homeip.net> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Wed, 15 Sep 2010 05:17:00 +0000 (UTC) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 8a42637..b2730b4 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -32,10 +32,9 @@ #include #include #include -#include #include #include -#include +#include #include MODULE_AUTHOR("Vojtech Pavlik "); @@ -44,7 +43,7 @@ MODULE_LICENSE("GPL"); /* * serio_mutex protects entire serio subsystem and is taken every time - * serio port or driver registrered or unregistered. + * serio port or driver registered or unregistered. */ static DEFINE_MUTEX(serio_mutex); @@ -165,58 +164,23 @@ struct serio_event { static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ static LIST_HEAD(serio_event_list); -static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static struct task_struct *serio_task; +static struct workqueue_struct *serio_wq; -static int serio_queue_event(void *object, struct module *owner, - enum serio_event_type event_type) +static struct serio_event *serio_get_event(void) { + struct serio_event *event = NULL; unsigned long flags; - struct serio_event *event; - int retval = 0; spin_lock_irqsave(&serio_event_lock, flags); - /* - * Scan event list for the other events for the same serio port, - * starting with the most recent one. If event is the same we - * do not need add new one. If event is of different type we - * need to add this event and should not look further because - * we need to preseve sequence of distinct events. - */ - list_for_each_entry_reverse(event, &serio_event_list, node) { - if (event->object == object) { - if (event->type == event_type) - goto out; - break; - } - } - - event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); - if (!event) { - pr_err("Not enough memory to queue event %d\n", event_type); - retval = -ENOMEM; - goto out; - } - - if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); - kfree(event); - retval = -EINVAL; - goto out; + if (!list_empty(&serio_event_list)) { + event = list_first_entry(&serio_event_list, + struct serio_event, node); + list_del_init(&event->node); } - event->type = event_type; - event->object = object; - event->owner = owner; - - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); - -out: spin_unlock_irqrestore(&serio_event_lock, flags); - return retval; + return event; } static void serio_free_event(struct serio_event *event) @@ -250,25 +214,7 @@ static void serio_remove_duplicate_events(struct serio_event *event) spin_unlock_irqrestore(&serio_event_lock, flags); } - -static struct serio_event *serio_get_event(void) -{ - struct serio_event *event = NULL; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); - - if (!list_empty(&serio_event_list)) { - event = list_first_entry(&serio_event_list, - struct serio_event, node); - list_del_init(&event->node); - } - - spin_unlock_irqrestore(&serio_event_lock, flags); - return event; -} - -static void serio_handle_event(void) +static void serio_handle_event(struct work_struct *work) { struct serio_event *event; @@ -307,6 +253,59 @@ static void serio_handle_event(void) mutex_unlock(&serio_mutex); } +static DECLARE_WORK(serio_event_work, serio_handle_event); + +static int serio_queue_event(void *object, struct module *owner, + enum serio_event_type event_type) +{ + unsigned long flags; + struct serio_event *event; + int retval = 0; + + spin_lock_irqsave(&serio_event_lock, flags); + + /* + * Scan event list for the other events for the same serio port, + * starting with the most recent one. If event is the same we + * do not need add new one. If event is of different type we + * need to add this event and should not look further because + * we need to preseve sequence of distinct events. + */ + list_for_each_entry_reverse(event, &serio_event_list, node) { + if (event->object == object) { + if (event->type == event_type) + goto out; + break; + } + } + + event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); + if (!event) { + pr_err("Not enough memory to queue event %d\n", event_type); + retval = -ENOMEM; + goto out; + } + + if (!try_module_get(owner)) { + pr_warning("Can't get module reference, dropping event %d\n", + event_type); + kfree(event); + retval = -EINVAL; + goto out; + } + + event->type = event_type; + event->object = object; + event->owner = owner; + + list_add_tail(&event->node, &serio_event_list); + queue_work(serio_wq, &serio_event_work); + +out: + spin_unlock_irqrestore(&serio_event_lock, flags); + return retval; +} + /* * Remove all events that have been submitted for a given * object, be it serio port or driver. @@ -358,18 +357,6 @@ static struct serio *serio_get_pending_child(struct serio *parent) return child; } -static int serio_thread(void *nothing) -{ - do { - serio_handle_event(); - wait_event_interruptible(serio_wait, - kthread_should_stop() || !list_empty(&serio_event_list)); - } while (!kthread_should_stop()); - - return 0; -} - - /* * Serio port operations */ @@ -996,17 +983,16 @@ static int __init serio_init(void) { int error; + serio_wq = alloc_workqueue("kseriod", WQ_UNBOUND, 1); + if (!serio_wq) { + pr_err("Failed to create kseriod workqueue\n"); + return -ENOMEM; + } + error = bus_register(&serio_bus); if (error) { pr_err("Failed to register serio bus, error: %d\n", error); - return error; - } - - serio_task = kthread_run(serio_thread, NULL, "kseriod"); - if (IS_ERR(serio_task)) { - bus_unregister(&serio_bus); - error = PTR_ERR(serio_task); - pr_err("Failed to start kseriod, error: %d\n", error); + destroy_workqueue(serio_wq); return error; } @@ -1016,7 +1002,7 @@ static int __init serio_init(void) static void __exit serio_exit(void) { bus_unregister(&serio_bus); - kthread_stop(serio_task); + destroy_workqueue(serio_wq); } subsys_initcall(serio_init);