Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 121966e in mainline


Ignore:
Timestamp:
2009-08-07T21:37:20Z (12 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
9732e98
Parents:
e31c2c5
Message:

task_done() should not kill tasks one by one and wait until each dies.
Instead, the kill needs to be signalled to all tasks and repeated as
long as there are any user tasks. Otherwise completion of a task kill
may depend on death of another task with a higher ID due to unanswered
calls.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/proc/task.c

    re31c2c5 r121966e  
    7575static task_id_t task_counter = 0;
    7676
     77/* Forward declarations. */
     78static void task_kill_internal(task_t *);
     79
    7780/** Initialize kernel tasks support. */
    7881void task_init(void)
     
    8386
    8487/*
    85  * The idea behind this walker is to remember a single task different from
     88 * The idea behind this walker is to kill and count all tasks different from
    8689 * TASK.
    8790 */
     
    8992{
    9093        task_t *t = avltree_get_instance(node, task_t, tasks_tree_node);
    91         task_t **tp = (task_t **) arg;
    92 
    93         if (t != TASK) {
    94                 *tp = t;
    95                 return false;   /* stop walking */
     94        unsigned *cnt = (unsigned *) arg;
     95
     96        if (t != TASK) {
     97                (*cnt)++;
     98#ifdef CONFIG_DEBUG
     99                printf("[%"PRIu64"] ", t->taskid);
     100#endif
     101                task_kill_internal(t);
    96102        }
    97103
     
    102108void task_done(void)
    103109{
    104         task_t *t;
     110        unsigned tasks_left;
     111
    105112        do { /* Repeat until there are any tasks except TASK */
    106                
    107113                /* Messing with task structures, avoid deadlock */
     114#ifdef CONFIG_DEBUG
     115                printf("Killing tasks... ");
     116#endif
    108117                ipl_t ipl = interrupts_disable();
    109118                spinlock_lock(&tasks_lock);
    110                
    111                 t = NULL;
    112                 avltree_walk(&tasks_tree, task_done_walker, &t);
    113                
    114                 if (t != NULL) {
    115                         task_id_t id = t->taskid;
    116                        
    117                         spinlock_unlock(&tasks_lock);
    118                         interrupts_restore(ipl);
    119                        
     119                tasks_left = 0;
     120                avltree_walk(&tasks_tree, task_done_walker, &tasks_left);
     121                spinlock_unlock(&tasks_lock);
     122                interrupts_restore(ipl);
     123                thread_sleep(1);
    120124#ifdef CONFIG_DEBUG
    121                         printf("Killing task %" PRIu64 "\n", id);
    122 #endif                 
    123                         task_kill(id);
    124                         thread_usleep(10000);
    125                 } else {
    126                         spinlock_unlock(&tasks_lock);
    127                         interrupts_restore(ipl);
    128                 }
    129                
    130         } while (t != NULL);
     125                printf("\n");
     126#endif
     127        } while (tasks_left);
    131128}
    132129
     
    350347}
    351348
    352 /** Kill task.
    353  *
    354  * This function is idempotent.
    355  * It signals all the task's threads to bail it out.
    356  *
    357  * @param id            ID of the task to be killed.
    358  *
    359  * @return              Zero on success or an error code from errno.h.
    360  */
    361 int task_kill(task_id_t id)
    362 {
    363         ipl_t ipl;
    364         task_t *ta;
     349static void task_kill_internal(task_t *ta)
     350{
    365351        link_t *cur;
    366352
    367         if (id == 1)
    368                 return EPERM;
    369        
    370         ipl = interrupts_disable();
    371         spinlock_lock(&tasks_lock);
    372         if (!(ta = task_find_by_id(id))) {
    373                 spinlock_unlock(&tasks_lock);
    374                 interrupts_restore(ipl);
    375                 return ENOENT;
    376         }
    377         spinlock_unlock(&tasks_lock);
    378        
    379353        /*
    380354         * Interrupt all threads.
     
    397371        }
    398372        spinlock_unlock(&ta->lock);
     373}
     374
     375/** Kill task.
     376 *
     377 * This function is idempotent.
     378 * It signals all the task's threads to bail it out.
     379 *
     380 * @param id            ID of the task to be killed.
     381 *
     382 * @return              Zero on success or an error code from errno.h.
     383 */
     384int task_kill(task_id_t id)
     385{
     386        ipl_t ipl;
     387        task_t *ta;
     388
     389        if (id == 1)
     390                return EPERM;
     391       
     392        ipl = interrupts_disable();
     393        spinlock_lock(&tasks_lock);
     394        if (!(ta = task_find_by_id(id))) {
     395                spinlock_unlock(&tasks_lock);
     396                interrupts_restore(ipl);
     397                return ENOENT;
     398        }
     399        task_kill_internal(ta);
     400        spinlock_unlock(&tasks_lock);
    399401        interrupts_restore(ipl);
    400        
    401402        return 0;
    402403}
Note: See TracChangeset for help on using the changeset viewer.