static void do_scheduled_release(struct vperfctr *child_perfctr) { struct task_struct *parent_tsk = child_perfctr->parent_tsk; task_lock(parent_tsk); do_vperfctr_release(child_perfctr, parent_tsk); task_unlock(parent_tsk); put_task_struct(parent_tsk); }
static void scheduled_release(struct work_struct *data) { struct vperfctr *child_perfctr = container_of(data, struct vperfctr, work); struct task_struct *parent_tsk = child_perfctr->parent_tsk; // why are we getting a lock on the parent task structure ? // of course, we incremented the reference count to parent's task_struct task_lock(parent_tsk); do_vperfctr_release(child_perfctr, parent_tsk); task_unlock(parent_tsk); // good, the incremented reference count of the parent task is now // decremented, now that we are done adding up our counts to that // of the parent put_task_struct(parent_tsk); }
void __vperfctr_release(struct task_struct *child_tsk) { struct task_struct *parent_tsk = child_tsk->parent; struct vperfctr *child_perfctr = child_tsk->thread.perfctr; // this is invoked either in the waitpid() or if there the parent is not // interesting in its children. In the latter case, "parent_tsk != current" // one releases oneself, when the parent is not interested in one's data // but even then we would like to add our counters to those of the parent's // another step towards freeing the task_struct(ure). child_tsk->thread.perfctr = NULL; // if the parent is releasing the children's task structure, then it (the // parent) can go ahead and add the children's vperfctr's values to the // 'children' field in the parent's 'vperfctr' structure. // So, am 'I' the parent of the task_structure I am attempting to release? // When current == parent_tsk, the child's counts can be merged // into the parent's immediately. This is the common case. // printk ("%s, %d\n", __FUNCTION__, __LINE__); if (child_perfctr == NULL) { // printk("%s, %d, child_perfctr == NULL\n", __FUNCTION__, __LINE__); } if (parent_tsk == current) do_vperfctr_release(child_perfctr, parent_tsk); else { /* When current != parent_tsk, the parent must be task_lock()ed * before its perfctr state can be accessed. task_lock() is illegal * here due to the write_lock_irq(&tasklist_lock) in release_task(), * so the operation is done via schedule_work(). Also, increment * the reference count of parent's task_struct so that it will not be * freed for good */ get_task_struct(parent_tsk); // increments the reference count INIT_WORK(&child_perfctr->work, scheduled_release); child_perfctr->parent_tsk = parent_tsk; schedule_work(&child_perfctr->work); } }
void __vperfctr_release(struct task_struct *child_tsk) { #if 0 struct task_struct *parent_tsk = child_tsk->parent; struct vperfctr *child_perfctr = child_tsk->arch.thread.perfctr; child_tsk->arch.thread.perfctr = NULL; if (parent_tsk == current) do_vperfctr_release(child_perfctr, parent_tsk); else { get_task_struct(parent_tsk); INIT_WORK(&child_perfctr->work, scheduled_release); child_perfctr->parent_tsk = parent_tsk; schedule_work(&child_perfctr->work); } #endif }