pagg
[Top] [All Lists]

[3/3] Re: CpuSet on PAGG (Re: PAGG in Open Source projects?)

To: Erik Jacobson <erikj@xxxxxxxxxxxxxxxxxxxxxxx>
Subject: [3/3] Re: CpuSet on PAGG (Re: PAGG in Open Source projects?)
From: Kaigai Kohei <kaigai@xxxxxxxxxxxxx>
Date: Thu, 27 Jan 2005 21:48:04 +0900
Cc: Kaigai Kohei <kaigai@xxxxxxxxxxxxx>, pagg@xxxxxxxxxxx, Limin Gu <limin@xxxxxxxxxxxxxxxxxx>, Paul Jackson <pj@xxxxxxx>, lse-tech@xxxxxxxxxxxxxxxxxxxxx, guillaume.thouvenin@xxxxxxxx
In-reply-to: <41F8E117.5030501@ak.jp.nec.com>
References: <Pine.SGI.4.53.0501181437280.627920@subway.americas.sgi.com> <41F8E117.5030501@ak.jp.nec.com>
Sender: pagg-bounce@xxxxxxxxxxx
User-agent: Mozilla Thunderbird 1.0 (Windows/20041206)
[3/3] linux-2.6.11-rc2-mm1-CpuSet_by_PAGG.patch
  We can use PAGG as the fork()/exit() event handling framework for generic 
purposes.
  Some functions, like as CpuSet, fit the PAGG framework, I think.

--
Linux Promotion Center, NEC
KaiGai Kohei <kaigai@xxxxxxxxxxxxx>


diff -rpNU3 linux-2.6.11-rc2-mm1.pagg/include/linux/pagg.h linux-2.6.11-rc2-mm1.pagg.rcu/include/linux/pagg.h --- linux-2.6.11-rc2-mm1.pagg/include/linux/pagg.h 2005-01-27 17:02:10.000000000 +0900 +++ linux-2.6.11-rc2-mm1.pagg.rcu/include/linux/pagg.h 2005-01-27 17:09:40.000000000 +0900 @@ -44,6 +44,7 @@ #define _LINUX_PAGG_H

 #include <linux/sched.h>
+#include <linux/rcupdate.h>

 #ifdef CONFIG_PAGG

@@ -57,8 +58,8 @@
  */
 #define INIT_PAGG_LIST(_l)                                             \
 do {                                                                   \
-       INIT_LIST_HEAD(&(_l)->pagg_list);                                       
 \
-       init_rwsem(&(_l)->pagg_sem);                                            
 \
+       INIT_LIST_HEAD(&(_l)->pagg_list);                                \
+       spin_lock_init(&(_l)->pagg_lock);                                \
 } while(0)
        

@@ -74,9 +75,10 @@ do {                                                         
        \
  *     entry:  List pointers
  */
 struct pagg {
-       struct pagg_hook        *hook;
-       void            *data;
-       struct list_head        entry;
+       struct pagg_hook        *hook;
+       void                    *data;
+       struct list_head        entry;
+       struct rcu_head         rhead;
 };

 /*
@@ -147,52 +149,10 @@ extern struct pagg *pagg_alloc(struct ta
 extern void pagg_free(struct pagg *pagg);
 extern int pagg_hook_register(struct pagg_hook *pt_new);
 extern int pagg_hook_unregister(struct pagg_hook *pt_old);
-extern int __pagg_attach(struct task_struct *to_task,
+extern int pagg_attach(struct task_struct *to_task,
                         struct task_struct *from_task);
-extern void __pagg_detach(struct task_struct *task);
-extern int __pagg_exec(struct task_struct *task);
-
-/**
- * pagg_attach - child inherits attachment to pagg containers of its parent
- * @child: child task - to inherit
- * @parent: parenet task - child inherits pagg containers from this parent
- *
- * function used when a child process must inherit attachment to pagg
- * containers from the parent.  Return code is propagated as a fork fail.
- *
- */
-static inline int pagg_attach(struct task_struct *child,
-                             struct task_struct *parent)
-{
-       INIT_PAGG_LIST(child);
-       if (!list_empty(&parent->pagg_list))
-               return __pagg_attach(child, parent);
-
-       return 0;
-}
-
-
-/**
- * pagg_detach - Detach a process from a pagg container it is a member of
- * @task: The task the pagg will be detached from
- *
- */
-static inline void pagg_detach(struct task_struct *task)
-{
-       if (!list_empty(&task->pagg_list))
-               __pagg_detach(task);
-}
-
-/**
- * pagg_exec - Used when a process exec's
- * @task: The process doing the exec
- *
- */
-static inline void pagg_exec(struct task_struct *task)
-{
-       if (!list_empty(&task->pagg_list))
-               __pagg_exec(task);
-}
+extern void pagg_detach(struct task_struct *task);
+extern int pagg_exec(struct task_struct *task);

 /**
  * INIT_TASK_PAGG - Used in INIT_TASK to set the head and sem of pagg_list
@@ -204,7 +164,7 @@ static inline void pagg_exec(struct task
  */
 #define INIT_TASK_PAGG(tsk) \
        .pagg_list = LIST_HEAD_INIT(tsk.pagg_list),     \
-       .pagg_sem  = __RWSEM_INITIALIZER(tsk.pagg_sem),
+       .pagg_lock = SPIN_LOCK_UNLOCKED,

 #else  /* CONFIG_PAGG */

diff -rpNU3 linux-2.6.11-rc2-mm1.pagg/include/linux/sched.h 
linux-2.6.11-rc2-mm1.pagg.rcu/include/linux/sched.h
--- linux-2.6.11-rc2-mm1.pagg/include/linux/sched.h     2005-01-27 
17:02:10.000000000 +0900
+++ linux-2.6.11-rc2-mm1.pagg.rcu/include/linux/sched.h 2005-01-27 
17:08:46.000000000 +0900
@@ -732,7 +732,7 @@ struct task_struct {
 #ifdef CONFIG_PAGG
 /* List of pagg (process aggregate) attachments */
        struct list_head pagg_list;
-       struct rw_semaphore pagg_sem;
+       spinlock_t pagg_lock;
 #endif

        struct list_head private_pages; /* per-process private pages */
diff -rpNU3 linux-2.6.11-rc2-mm1.pagg/kernel/pagg.c 
linux-2.6.11-rc2-mm1.pagg.rcu/kernel/pagg.c
--- linux-2.6.11-rc2-mm1.pagg/kernel/pagg.c     2005-01-27 17:02:10.000000000 
+0900
+++ linux-2.6.11-rc2-mm1.pagg.rcu/kernel/pagg.c 2005-01-27 17:35:53.000000000 
+0900
@@ -45,16 +45,15 @@ static DECLARE_RWSEM(pagg_hook_list_sem)
  * a pointer to the pagg struct that matches the search
  * key.  If the key is not found, the function will return NULL.
  *
- * The caller should hold at least a read lock on the pagg_list
- * for task using down_read(&task->pagg_list.sem).
- *
+ * The caller must be under the rcu_read_lock(), and the existance
+ * of the object which is returned is guaranteed by rcu_read_unlock().
  */
 struct pagg *
 pagg_get(struct task_struct *task, char *key)
 {
        struct pagg *pagg;

-       list_for_each_entry(pagg, &task->pagg_list, entry) {
+       list_for_each_entry_rcu(pagg, &task->pagg_list, entry) {
                if (!strcmp(pagg->hook->name,key))
                        return pagg;
        }
@@ -74,24 +73,36 @@ pagg_get(struct task_struct *task, char
  * The caller for this function should hold at least a read lock on the
  * pagg_hook_list_sem - or ensure that the pagg hook entry cannot be
  * removed. If this function was called from the pagg module (usually the
- * case), then the caller need not hold this lock. The caller should hold
- * a write lock on for the tasks pagg_sem.  This can be locked using
- * down_write(&task->pagg_sem)
+ * case), then the caller need not hold this lock. The caller must hold
+ * a spin lock on for the tasks pagg_lock.  This can be locked using
+ * spin_lock(&task->pagg_lock)
  *
  */
-struct pagg *
-pagg_alloc(struct task_struct *task, struct pagg_hook *pagg_hook)
+static struct pagg *
+__pagg_alloc(struct task_struct *task, struct pagg_hook *pagg_hook)
 {
        struct pagg *pagg;

        pagg = kmalloc(sizeof(struct pagg), GFP_KERNEL);
        if (!pagg)
                return NULL;
-
        pagg->hook = pagg_hook;
        pagg->data = NULL;
+       INIT_LIST_HEAD(&pagg->entry);
        atomic_inc(&pagg_hook->refcnt);  /* Increase hook's reference count */
-       list_add_tail(&pagg->entry, &task->pagg_list);
+
+       return pagg;
+}
+
+struct pagg *
+pagg_alloc(struct task_struct *task, struct pagg_hook *pagg_hook)
+{
+       struct pagg *pagg;
+
+       pagg = __pagg_alloc(task, pagg_hook);
+       if (!pagg)
+               return NULL;
+       list_add_tail_rcu(&pagg->entry, &task->pagg_list);
        return pagg;
 }

@@ -100,24 +111,37 @@ pagg_alloc(struct task_struct *task, str
  * pagg_free - Delete pagg from the list and free its memory
  * @pagg: The pagg to free
  *
- * This function will ensure the pagg is deleted form
+ * This function will ensure the pagg is deleted from
  * the list of pagg entries for the task. Finally, the memory for the
  * pagg is discarded.
  *
- * The caller of this function should hold a write lock on the pagg_sem
- * for the task. This can be locked using down_write(&task->pagg_sem).
+ * The caller of this function must hold a spin lock on the pagg_list
+ * for the task. This can be locked using spin_lock(&task->pagg_list).
  *
  * Prior to calling pagg_free, the pagg should have been detached from the
  * pagg container represented by this pagg.  That is usually done using
  * p->hook->detach(task, pagg);
  *
  */
+static void
+rcu_pagg_free(struct rcu_head *rhead)
+{
+       struct pagg *pg = container_of(rhead, struct pagg, rhead);
+       kfree(pg);
+}
+
+static void
+__pagg_free(struct pagg *pagg)
+{
+       atomic_dec(&pagg->hook->refcnt); /* decr the reference count on the 
hook */
+       call_rcu(&pagg->rhead, rcu_pagg_free);
+}
+
 void
 pagg_free(struct pagg *pagg)
 {
-       atomic_dec(&pagg->hook->refcnt); /* decr the reference count on the 
hook */
-       list_del(&pagg->entry);
-       kfree(pagg);
+       list_del_rcu(&pagg->entry);
+       __pagg_free(pagg);
 }


@@ -181,13 +205,20 @@ remove_client_paggs_from_all_tasks(struc

                        get_task_struct(p);
                        read_unlock(&tasklist_lock);
-                       down_write(&p->pagg_sem);
+
+                       rcu_read_lock();
+                       spin_lock(&p->pagg_lock);
                        paggp = pagg_get(p, php->name);
                        if (paggp != NULL) {
+                               list_del_rcu(&paggp->entry);
+                               spin_unlock(&p->pagg_lock);
                                (void)php->detach(p, paggp);
-                               pagg_free(paggp);
+                               __pagg_free(paggp);
+                       } else {
+                               spin_unlock(&p->pagg_lock);
                        }
-                       up_write(&p->pagg_sem);
+                       rcu_read_unlock();
+
                        read_lock(&tasklist_lock);

                        /* If a PAGG got removed from the list while we're 
going through
@@ -275,21 +306,24 @@ pagg_hook_register(struct pagg_hook *pag

                        get_task_struct(p);
                        read_unlock(&tasklist_lock);
-                       down_write(&p->pagg_sem);
+                       
+                       spin_lock(&p->pagg_lock);
                        paggp = pagg_get(p, pagg_hook_new->name);
                        if (!paggp && !(p->flags & PF_EXITING)) {
-                               paggp = pagg_alloc(p, pagg_hook_new);
+                               paggp = __pagg_alloc(p, pagg_hook_new);
                                if (paggp != NULL) {
                                        init_result = pagg_hook_new->init(p, 
paggp);
-
-                                       /* Success, but init function pointer 
doesn't want grouping */
-                                       if (init_result > 0)
-                                               pagg_free(paggp);
-                               }
-                               else
+                                       if (init_result == 0) {
+                                               list_add_tail_rcu(&paggp->entry, 
&p->pagg_list);
+                                       } else {
+                                               __pagg_free(paggp);
+                                       }
+                               } else {
                                        init_result = -ENOMEM;
+                               }
                        }
-                       up_write(&p->pagg_sem);
+                       spin_unlock(&p->pagg_lock);
+
                        read_lock(&tasklist_lock);
                        /* Like in remove_client_paggs_from_all_tasks, if the 
task
                         * disappeared on us while we were going through the
@@ -388,41 +422,46 @@ pagg_hook_unregister(struct pagg_hook *p
  * The "from" argument is the parent task.  The "to" argument is the child
  * task.
  *
- * See the attach decription in linux/include/linux/pagg.h for details on
- * how to handle return codes from the attach function pointer.
- *
+ * The child task must not be referenced yet.
  */
 int
-__pagg_attach(struct task_struct *to_task, struct task_struct *from_task)
+pagg_attach(struct task_struct *to_task, struct task_struct *from_task)
 {
        struct pagg *from_pagg;
        int ret;

-       /* lock the parents pagg_list we are copying from */
-       down_read(&from_task->pagg_sem); /* read lock the pagg list */
+       INIT_PAGG_LIST(to_task);
+
+       rcu_read_lock();

+       if (list_empty(&from_task->pagg_list)) {
+               rcu_read_unlock();
+               return 0;
+       }
+
+       /* lock the parents pagg_list we are copying from */
        list_for_each_entry(from_pagg, &from_task->pagg_list, entry) {
                struct pagg *to_pagg = NULL;

-               to_pagg = pagg_alloc(to_task, from_pagg->hook);
+               to_pagg = __pagg_alloc(to_task, from_pagg->hook);
                if (!to_pagg) {
                        ret=-ENOMEM;
                        goto error_return;
                }
                ret = to_pagg->hook->attach(to_task, to_pagg, from_pagg->data);
-
-               if (ret < 0) {
+               if (likely(ret==0)) {
+                       /* Success, and PAGG will be chained */
+                       list_add_tail_rcu(&to_pagg->entry, &to_task->pagg_list);
+               } else if (ret < 0) {
                        /* Propagates to copy_process as a fork failure */
                        goto error_return;
-               }
-               else if (ret > 0) {
+               } else {
                        /* Success, but attach function pointer doesn't want 
grouping */
-                       pagg_free(to_pagg);
+                       __pagg_free(to_pagg);
                }
        }

-       up_read(&from_task->pagg_sem); /* unlock the pagg list */
-
+       rcu_read_unlock();
        return 0;                                       /* success */

   error_return:
@@ -430,8 +469,8 @@ __pagg_attach(struct task_struct *to_tas
         * Clean up all the pagg attachments made on behalf of the new
         * task.  Set new task pagg ptr to NULL for return.
         */
-       up_read(&from_task->pagg_sem); /* unlock the pagg list */
-       __pagg_detach(to_task);
+       rcu_read_unlock();
+       pagg_detach(to_task);
        return ret;                             /* failure */
 }

@@ -443,21 +482,28 @@ __pagg_attach(struct task_struct *to_tas
  *
  */
 void
-__pagg_detach(struct task_struct *task)
+pagg_detach(struct task_struct *task)
 {
        struct pagg *pagg;
        struct pagg *paggtmp;

-       /* Remove ref. to paggs from task immediately */
-       down_write(&task->pagg_sem); /* write lock pagg list */
+       rcu_read_lock();
+       if (list_empty(&task->pagg_list))
+               goto out;

+       spin_lock(&task->pagg_lock);
        list_for_each_entry_safe(pagg, paggtmp, &task->pagg_list, entry) {
-               pagg->hook->detach(task, pagg);
-               pagg_free(pagg);
-       }
+               list_del_rcu(&pagg->entry);
+               spin_unlock(&task->pagg_lock);

-       up_write(&task->pagg_sem); /* write unlock the pagg list */
+               pagg->hook->detach(task, pagg);
+               __pagg_free(pagg);

+               spin_lock(&task->pagg_lock);
+       }
+       spin_unlock(&task->pagg_lock);
+out:
+       rcu_read_unlock();
        return;   /* 0 = success, else return last code for failure */
 }

@@ -473,18 +519,20 @@ __pagg_detach(struct task_struct *task)
  *
  */
 int
-__pagg_exec(struct task_struct *task)
+pagg_exec(struct task_struct *task)
 {
        struct pagg     *pagg;

-       down_read(&task->pagg_sem); /* lock the pagg list */
+       rcu_read_lock();
+       if (list_empty(&task->pagg_list))
+               goto out;

-       list_for_each_entry(pagg, &task->pagg_list, entry) {
+       list_for_each_entry_rcu(pagg, &task->pagg_list, entry) {
                if (pagg->hook->exec) /* conditional because it's optional */
                        pagg->hook->exec(task, pagg);
        }
-
-       up_read(&task->pagg_sem); /* unlock the pagg list */
+ out:
+       rcu_read_unlock();
        return 0;
 }



<Prev in Thread] Current Thread [Next in Thread>