Changeset 035d7d8 in mainline


Ignore:
Timestamp:
2019-08-07T05:49:44Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
2aaccd3
Parents:
456f7ae
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-10-21 22:44:26)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-07 05:49:44)
Message:

taskman: Implement task event notifications

Location:
uspace
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/tester/proc/task_anywait.c

    r456f7ae r035d7d8  
    6060
    6161        handler_hit = true;
     62        if (flags & TASK_WAIT_EXIT) {
     63                last_texit = texit;
     64        }
     65
     66        last_has_retval = flags & TASK_WAIT_RETVAL;
     67        if (last_has_retval) {
     68                last_retval = retval;
     69        }
     70
    6271finish:
    6372        fibril_condvar_signal(&sync_cv);
  • uspace/srv/net/tcp/service.c

    r456f7ae r035d7d8  
    3535 */
    3636
    37 #include <async.h>
    3837#include <errno.h>
    3938#include <str_error.h>
  • uspace/srv/taskman/Makefile

    r456f7ae r035d7d8  
    3232
    3333SOURCES = \
     34        event.c \
    3435        main.c \
    3536        task.c
  • uspace/srv/taskman/main.c

    r456f7ae r035d7d8  
    3939#include <stdlib.h>
    4040
     41#include "event.h"
    4142#include "task.h"
    4243#include "taskman.h"
     
    6364       
    6465        if (rc != EOK) {
     66                printf(NAME ": %s -> %i\n", __func__, rc);
    6567                async_answer_0(iid, rc);
    6668                return;
     
    125127{
    126128        printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
    127         async_answer_0(iid, ENOTSUP); // TODO interrupt here
     129        /* Atomic -- will be used for notifications only */
     130        async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
     131        if (sess == NULL) {
     132                async_answer_0(iid, ENOMEM);
     133                return;
     134        }
     135
     136        int rc = event_register_listener(icall->in_task_id, sess);
     137        async_answer_0(iid, rc);
    128138}
    129139
     
    268278                return rc;
    269279        }
     280        rc = event_init();
     281        if (rc != EOK) {
     282                return rc;
     283        }
    270284
    271285        rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
  • uspace/srv/taskman/task.c

    r456f7ae r035d7d8  
    3030
    3131/**
    32  * locking order:
     32 * locking order: (TODO move to main?)
    3333 * - task_hash_table_lock,
    3434 * - pending_wait_lock.
     35 * - listeners_lock
    3536 *
    3637 * @addtogroup taskman
     
    3839 */
    3940
    40 #include <adt/hash_table.h>
    4141#include <assert.h>
    4242#include <async.h>
    4343#include <errno.h>
    44 #include <fibril_synch.h>
    4544#include <macros.h>
    4645#include <malloc.h>
     
    5352#include "taskman.h"
    5453
    55 /** what type of retval from the task we have */
    56 typedef enum {
    57         RVAL_UNSET,     /**< unset */
    58         RVAL_SET,       /**< retval set, e.g. by server */
    59         RVAL_SET_EXIT   /**< retval set, wait for expected task exit */
    60 } retval_t;
    61 
    62 /** Task hash table item. */
    63 typedef struct {
    64         ht_link_t link;
    65        
    66         task_id_t id;          /**< Task id. */
    67         task_exit_t exit;      /**< Task's uspace exit status. */
    68         bool failed;           /**< Task failed. */
    69         retval_t retval_type;  /**< Task returned a value. */
    70         int retval;            /**< The return value. */
    71 } hashed_task_t;
    72 
    73 
    7454static size_t task_key_hash(void *key)
    7555{
     
    7959static size_t task_hash(const ht_link_t  *item)
    8060{
    81         hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
     61        task_t *ht = hash_table_get_inst(item, task_t, link);
    8262        return ht->id;
    8363}
     
    8565static bool task_key_equal(void *key, const ht_link_t *item)
    8666{
    87         hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
     67        task_t *ht = hash_table_get_inst(item, task_t, link);
    8868        return ht->id == *(task_id_t*)key;
    8969}
     
    9272static void task_remove(ht_link_t *item)
    9373{
    94         free(hash_table_get_inst(item, hashed_task_t, link));
     74        free(hash_table_get_inst(item, task_t, link));
    9575}
    9676
     
    10585
    10686/** Task hash table structure. */
    107 static hash_table_t task_hash_table;
    108 static FIBRIL_RWLOCK_INITIALIZE(task_hash_table_lock);
    109 
    110 /** Pending task wait structure. */
    111 typedef struct {
    112         link_t link;
    113         task_id_t id;         /**< Task ID who we wait for. */
    114         task_id_t waiter_id;  /**< Task ID who waits. */
    115         ipc_callid_t callid;  /**< Call ID waiting for the connection */
    116         int flags;            /**< Wait flags */
    117 } pending_wait_t;
    118 
    119 static list_t pending_wait;
    120 static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock);
     87hash_table_t task_hash_table;
     88fibril_rwlock_t task_hash_table_lock;
    12189
    12290int task_init(void)
     
    12694                return ENOMEM;
    12795        }
     96
     97        fibril_rwlock_initialize(&task_hash_table_lock);
    12898       
    129         list_initialize(&pending_wait);
    13099        return EOK;
    131100}
    132101
    133 /** Process pending wait requests
     102/** Find task by its ID
    134103 *
    135  * Assumes task_hash_table_lock is hold (at least read)
     104 * Assumes held lock of task_hash_table.
     105 *
     106 * @param[in]  id
     107 * @return task structure
     108 * @return NULL when no task with given ID exists
    136109 */
    137 void process_pending_wait(void)
     110task_t *task_get_by_id(task_id_t id)
    138111{
    139         fibril_rwlock_write_lock(&pending_wait_lock);
    140 loop:
    141         list_foreach(pending_wait, link, pending_wait_t, pr) {
    142                 ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
    143                 if (!link)
    144                         continue;
    145                
    146                 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    147                 int notify_flags = 0;
    148                 if (ht->exit != TASK_EXIT_RUNNING) {
    149                         notify_flags |= TASK_WAIT_EXIT;
    150                         if (ht->retval_type == RVAL_SET_EXIT) {
    151                                 notify_flags |= TASK_WAIT_RETVAL;
    152                         }
    153                 }
    154                 if (ht->retval_type == RVAL_SET) {
    155                         notify_flags |= TASK_WAIT_RETVAL;
    156                 }
    157 
    158                 /*
    159                  * In current implementation you can wait for single retval,
    160                  * thus it can be never present in rest flags.
    161                  */
    162                 int rest = (~notify_flags & pr->flags) & ~TASK_WAIT_RETVAL;
    163                 rest &= ~TASK_WAIT_BOTH;
    164                 int match = notify_flags & pr->flags;
    165                 bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);
    166                 printf("%s: %x; %x, %x\n", __func__, pr->flags, rest, match);
    167 
    168                 if (match == 0) {
    169                         if (notify_flags & TASK_WAIT_EXIT) {
    170                                 /* Nothing to wait for anymore */
    171                                 if (answer) {
    172                                         async_answer_0(pr->callid, EINVAL);
    173                                 }
    174                         } else {
    175                                 /* Maybe later */
    176                                 continue;
    177                         }
    178                 } else if (answer) {
    179                         if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {
    180                                 async_answer_1(pr->callid, EINVAL, ht->exit);
    181                         } else {
    182                                 /* Send both exit status and retval, caller
    183                                  * should know what is valid */
    184                                 async_answer_3(pr->callid, EOK, ht->exit,
    185                                     ht->retval, rest);
    186                         }
    187 
    188                         /* Pending wait has one more chance  */
    189                         if (rest && (pr->flags & TASK_WAIT_BOTH)) {
    190                                 pr->flags = rest | TASK_WAIT_BOTH;
    191                                 continue;
    192                         }
    193                 }
    194 
    195                
    196                 list_remove(&pr->link);
    197                 free(pr);
    198                 goto loop;
    199         }
    200         fibril_rwlock_write_unlock(&pending_wait_lock);
    201 }
    202 
    203 void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)
    204 {
    205         assert(!(flags & TASK_WAIT_BOTH) ||
    206             ((flags & TASK_WAIT_RETVAL) && (flags & TASK_WAIT_EXIT)));
    207 
    208         fibril_rwlock_read_lock(&task_hash_table_lock);
    209112        ht_link_t *link = hash_table_find(&task_hash_table, &id);
    210         fibril_rwlock_read_unlock(&task_hash_table_lock);
    211 
    212         hashed_task_t *ht = (link != NULL) ?
    213             hash_table_get_inst(link, hashed_task_t, link) : NULL;
    214        
    215         if (ht == NULL) {
    216                 /* No such task exists. */
    217                 async_answer_0(callid, ENOENT);
    218                 return;
     113        if (!link) {
     114                return NULL;
    219115        }
    220116       
    221         if (ht->exit != TASK_EXIT_RUNNING) {
    222                 //TODO are flags BOTH processed correctly here?
    223                 async_answer_3(callid, EOK, ht->exit, ht->retval, 0);
    224                 return;
    225         }
    226        
    227         /*
    228          * Add request to pending list or reuse existing item for a second
    229          * wait.
    230          */
    231         task_id_t waiter_id = call->in_task_id;
    232         fibril_rwlock_write_lock(&pending_wait_lock);
    233         pending_wait_t *pr = NULL;
    234         list_foreach(pending_wait, link, pending_wait_t, it) {
    235                 if (it->id == id && it->waiter_id == waiter_id) {
    236                         pr = it;
    237                         break;
    238                 }
    239         }
    240 
    241         int rc = EOK;
    242         bool reuse = false;
    243         if (pr == NULL) {
    244                 pr = malloc(sizeof(pending_wait_t));
    245                 if (!pr) {
    246                         rc = ENOMEM;
    247                         goto finish;
    248                 }
    249        
    250                 link_initialize(&pr->link);
    251                 pr->id = id;
    252                 pr->waiter_id = waiter_id;
    253                 pr->flags = flags;
    254                 pr->callid = callid;
    255 
    256                 list_append(&pr->link, &pending_wait);
    257                 rc = EOK;
    258         } else if (!(pr->flags & TASK_WAIT_BOTH)) {
    259                 /*
    260                  * One task can wait for another task only once (per task, not
    261                  * fibril).
    262                  */
    263                 rc = EEXISTS;
    264         } else {
    265                 /*
    266                  * Reuse pending wait for the second time.
    267                  */
    268                 pr->flags &= ~TASK_WAIT_BOTH; // TODO maybe new flags should be set?
    269                 pr->callid = callid;
    270                 reuse = true;
    271         }
    272         printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse);
    273 
    274 finish:
    275         fibril_rwlock_write_unlock(&pending_wait_lock);
    276         // TODO why IPC_CALLID_NOTIFICATION? explain!
    277         if (rc != EOK && !(callid & IPC_CALLID_NOTIFICATION))
    278                 async_answer_0(callid, rc);
    279 
     117        task_t *t = hash_table_get_inst(link, task_t, link);
     118        return t;
    280119}
    281120
     
    286125        fibril_rwlock_write_lock(&task_hash_table_lock);
    287126
    288         ht_link_t *link = hash_table_find(&task_hash_table, &call->in_task_id);
    289         if (link != NULL) {
     127        task_t *t = task_get_by_id(call->in_task_id);
     128        if (t != NULL) {
    290129                rc = EEXISTS;
    291130                goto finish;
    292131        }
    293132       
    294         hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
    295         if (ht == NULL) {
     133        t = malloc(sizeof(task_t));
     134        if (t == NULL) {
    296135                rc = ENOMEM;
    297136                goto finish;
     
    301140         * Insert into the main table.
    302141         */
    303         ht->id = call->in_task_id;
    304         ht->exit = TASK_EXIT_RUNNING;
    305         ht->failed = false;
    306         ht->retval_type = RVAL_UNSET;
    307         ht->retval = -1;
     142        t->id = call->in_task_id;
     143        t->exit = TASK_EXIT_RUNNING;
     144        t->failed = false;
     145        t->retval_type = RVAL_UNSET;
     146        t->retval = -1;
     147        link_initialize(&t->listeners);
     148        t->sess = NULL;
    308149
    309         hash_table_insert(&task_hash_table, &ht->link);
    310         printf("%s: %llu\n", __func__, ht->id);
     150        hash_table_insert(&task_hash_table, &t->link);
     151        printf("%s: %llu\n", __func__, t->id);
    311152       
    312153finish:
     
    315156}
    316157
    317 int task_set_retval(ipc_call_t *call)
    318 {
    319         int rc = EOK;
    320         task_id_t id = call->in_task_id;
    321        
    322         fibril_rwlock_write_lock(&task_hash_table_lock);
    323         ht_link_t *link = hash_table_find(&task_hash_table, &id);
    324 
    325         hashed_task_t *ht = (link != NULL) ?
    326             hash_table_get_inst(link, hashed_task_t, link) : NULL;
    327        
    328         if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) {
    329                 rc = EINVAL;
    330                 goto finish;
    331         }
    332        
    333         ht->retval = IPC_GET_ARG1(*call);
    334         ht->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET;
    335        
    336         process_pending_wait();
    337        
    338 finish:
    339         fibril_rwlock_write_unlock(&task_hash_table_lock);
    340         return rc;
    341 }
    342 
    343 void task_terminated(task_id_t id, exit_reason_t exit_reason)
    344 {
    345         /* Mark task as finished. */
    346         fibril_rwlock_write_lock(&task_hash_table_lock);
    347         ht_link_t *link = hash_table_find(&task_hash_table, &id);
    348         if (link == NULL) {
    349                 goto finish;
    350         }
    351 
    352         hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    353        
    354         /*
    355          * If daemon returns a value and then fails/is killed, it's an
    356          * unexpected termination.
    357          */
    358         if (ht->retval_type == RVAL_UNSET || exit_reason == EXIT_REASON_KILLED) {
    359                 ht->exit = TASK_EXIT_UNEXPECTED;
    360         } else if (ht->failed) {
    361                 ht->exit = TASK_EXIT_UNEXPECTED;
    362         } else  {
    363                 ht->exit = TASK_EXIT_NORMAL;
    364         }
    365         process_pending_wait();
    366 
    367         hash_table_remove_item(&task_hash_table, &ht->link);
    368 finish:
    369         fibril_rwlock_write_unlock(&task_hash_table_lock);
    370 }
    371 
    372 void task_failed(task_id_t id)
    373 {
    374         /* Mark task as failed. */
    375         fibril_rwlock_write_lock(&task_hash_table_lock);
    376         ht_link_t *link = hash_table_find(&task_hash_table, &id);
    377         if (link == NULL) {
    378                 goto finish;
    379         }
    380 
    381         hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    382        
    383         ht->failed = true;
    384         // TODO design substitution for taskmon (monitoring) = invoke dump utility
    385 
    386 finish:
    387         fibril_rwlock_write_unlock(&task_hash_table_lock);
    388 }
    389158
    390159/**
  • uspace/srv/taskman/task.h

    r456f7ae r035d7d8  
    3535#define TASKMAN_TASK_H__
    3636
     37#include <abi/proc/task.h>
     38#include <adt/hash_table.h>
     39#include <adt/list.h>
     40#include <fibril_synch.h>
    3741#include <ipc/common.h>
    38 #include <abi/proc/task.h>
     42
     43/** What type of retval from the task we have */
     44typedef enum {
     45        RVAL_UNSET,     /**< unset */
     46        RVAL_SET,       /**< retval set, e.g. by server */
     47        RVAL_SET_EXIT   /**< retval set, wait for expected task exit */
     48} retval_t;
     49
     50/** Holds necessary information of each (registered) task. */
     51typedef struct {
     52        ht_link_t link;
     53       
     54        task_id_t id;          /**< Task id. */
     55        task_exit_t exit;      /**< Task's uspace exit status. */
     56        bool failed;           /**< Task failed (task can exit unexpectedly
     57                                    even w/out failure). */
     58        retval_t retval_type;  /**< Task returned a value. */
     59        int retval;            /**< The return value. */
     60
     61        link_t listeners;      /**< Link to listeners list. */
     62        async_sess_t *sess;    /**< Session for notifications to task. */
     63} task_t;
     64
     65extern hash_table_t task_hash_table;
     66extern fibril_rwlock_t task_hash_table_lock;
    3967
    4068extern int task_init(void);
    41 extern void process_pending_wait(void);
    4269
    43 extern void wait_for_task(task_id_t, int, ipc_callid_t, ipc_call_t *);
    44 extern int task_set_retval(ipc_call_t *);
     70extern task_t *task_get_by_id(task_id_t);
    4571
    4672extern int task_intro(ipc_call_t *, bool);
    47 extern void task_terminated(task_id_t, exit_reason_t);
    48 extern void task_failed(task_id_t);
    4973
    5074#endif
Note: See TracChangeset for help on using the changeset viewer.