Changeset d4ec49e in mainline


Ignore:
Timestamp:
2019-08-07T05:25:59Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
3ea98e8
Parents:
55fe220
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-10-14 23:13:41)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-07 05:25:59)
Message:

taskman: Implement waiting both for retval and exit
Conflicts:

uspace/lib/c/generic/task.c
uspace/lib/c/include/task.h

Location:
uspace
Files:
5 edited

Legend:

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

    r55fe220 rd4ec49e  
    7474
    7575        TPRINTF("waiting...");
    76         rc = task_wait(&wait, &texit, &retval);
    77         TPRINTF("done.\n");
    78         TASSERT(rc == EOK);
     76        texit = TASK_EXIT_RUNNING; retval = 255;
     77        rc = task_wait(&wait, &texit, &retval);
     78        TPRINTF("done.\n");
     79        TASSERT(rc == EOK);
     80        TASSERT(task_wait_get(&wait) == 0);
    7981        TASSERT(texit == TASK_EXIT_UNEXPECTED);
    8082        TPRINTF("OK\n");
     
    8890
    8991        TPRINTF("waiting...");
     92        texit = TASK_EXIT_RUNNING; retval = 255;
    9093        rc = task_wait(&wait, &texit, &retval);
    9194        TPRINTF("done.\n");
    9295        TASSERT(rc == EINVAL);
     96        TASSERT(task_wait_get(&wait) == 0);
    9397        TPRINTF("OK\n");
    9498        /* ---- */
     
    101105
    102106        TPRINTF("waiting...");
    103         rc = task_wait(&wait, &texit, &retval);
    104         TPRINTF("done.\n");
    105         TASSERT(rc == EOK);
     107        texit = TASK_EXIT_RUNNING; retval = 255;
     108        rc = task_wait(&wait, &texit, &retval);
     109        TPRINTF("done.\n");
     110        TASSERT(rc == EOK);
     111        TASSERT(task_wait_get(&wait) == 0);
    106112        TASSERT(texit == TASK_EXIT_UNEXPECTED);
    107113        /* retval is undefined */
     
    109115        /* ---- */
    110116
    111         TPRINTF("21 ignore retval\n");
     117        TPRINTF("21 ignore retval and still wait for exit\n");
    112118
    113119        task_wait_set(&wait, TASK_WAIT_EXIT);
    114         rc = dummy_task_spawn(&tid, &wait, STR_JOB_OK);
    115         TASSERT(rc == EOK);
    116 
    117         TPRINTF("waiting...");
    118         rc = task_wait(&wait, &texit, &retval);
    119         TPRINTF("done.\n");
    120         TASSERT(rc == EOK);
     120        /* STR_JOB_OK to emulate daemon that eventually terminates */
     121        rc = dummy_task_spawn(&tid, &wait, STR_JOB_OK);
     122        TASSERT(rc == EOK);
     123
     124        TPRINTF("waiting...");
     125        texit = TASK_EXIT_RUNNING; retval = 255;
     126        rc = task_wait(&wait, &texit, &retval);
     127        TPRINTF("done.\n");
     128        TASSERT(rc == EOK);
     129        TASSERT(task_wait_get(&wait) == 0);
    121130        TASSERT(texit == TASK_EXIT_NORMAL);
    122131        /* retval is unknown */
     
    131140
    132141        TPRINTF("waiting...");
    133         rc = task_wait(&wait, &texit, &retval);
    134         TPRINTF("done.\n");
    135         TASSERT(rc == EOK);
     142        texit = TASK_EXIT_RUNNING; retval = 255;
     143        rc = task_wait(&wait, &texit, &retval);
     144        TPRINTF("done.\n");
     145        TASSERT(rc == EOK);
     146        TASSERT(task_wait_get(&wait) == 0);
    136147        /* exit is not expected */
    137148        TASSERT(retval == EOK);
     
    142153        TPRINTF("23 partial match (non-exited task)\n");
    143154
    144         // TODO should update wait for synchronized exit waiting
    145155        task_wait_set(&wait, TASK_WAIT_RETVAL | TASK_WAIT_EXIT);
    146156        rc = dummy_task_spawn(&tid, &wait, STR_DAEMON);
     
    148158
    149159        TPRINTF("waiting...");
    150         rc = task_wait(&wait, &texit, &retval);
    151         TPRINTF("done.\n");
    152         TASSERT(rc == EOK);
     160        texit = TASK_EXIT_RUNNING; retval = 255;
     161        rc = task_wait(&wait, &texit, &retval);
     162        TPRINTF("done.\n");
     163        TASSERT(rc == EOK);
     164        TASSERT(task_wait_get(&wait) == TASK_WAIT_EXIT);
    153165        /* exit is not expected */
    154166        TASSERT(retval == EOK);
     
    164176
    165177        TPRINTF("waiting...");
    166         rc = task_wait(&wait, &texit, &retval);
    167         TPRINTF("done.\n");
    168         TASSERT(rc == EOK);
     178        texit = TASK_EXIT_RUNNING; retval = 255;
     179        rc = task_wait(&wait, &texit, &retval);
     180        TPRINTF("done.\n");
     181        TASSERT(rc == EOK);
     182        TASSERT(task_wait_get(&wait) == 0);
    169183        TASSERT(texit == TASK_EXIT_NORMAL);
    170184        /* retval is unknown */
     
    180194
    181195        TPRINTF("waiting...");
    182         rc = task_wait(&wait, &texit, &retval);
    183         TPRINTF("done.\n");
    184         TASSERT(rc == EOK);
     196        texit = TASK_EXIT_RUNNING; retval = 255;
     197        rc = task_wait(&wait, &texit, &retval);
     198        TPRINTF("done.\n");
     199        TASSERT(rc == EOK);
     200        /* Job atomically exited, so there's nothing more to wait for. */
     201        TASSERT(task_wait_get(&wait) == 0);
    185202        /* exit is unknown */
    186203        TASSERT(retval == EOK);
     
    198215
    199216        TPRINTF("waiting...");
    200         rc = task_wait(&wait, &texit, &retval);
    201         TPRINTF("done.\n");
    202         TASSERT(rc == EOK);
     217        texit = TASK_EXIT_RUNNING; retval = 255;
     218        rc = task_wait(&wait, &texit, &retval);
     219        TPRINTF("done.\n");
     220        TASSERT(rc == EOK);
     221        TASSERT(task_wait_get(&wait) == 0);
     222        TASSERT(texit == TASK_EXIT_NORMAL);
     223        TASSERT(retval == EOK);
     224        TPRINTF("OK\n");
     225        /* ---- */
     226
     227        TPRINTF("14 partially lost wait\n");
     228
     229        task_wait_set(&wait, TASK_WAIT_BOTH);
     230        rc = dummy_task_spawn(&tid, &wait, STR_FAIL);
     231        TASSERT(rc == EOK);
     232
     233        TPRINTF("waiting...");
     234        texit = TASK_EXIT_RUNNING; retval = 255;
     235        rc = task_wait(&wait, &texit, &retval);
     236        TPRINTF("done.\n");
     237        TASSERT(rc == EINVAL);
     238        TASSERT(task_wait_get(&wait) == 0);
     239        TASSERT(texit == TASK_EXIT_UNEXPECTED);
     240        /* retval is undefined */
     241        TPRINTF("OK\n");
     242        /* ---- */
     243
     244        TPRINTF("24 repeated wait\n");
     245
     246        task_wait_set(&wait, TASK_WAIT_BOTH);
     247        rc = dummy_task_spawn(&tid, &wait, STR_DAEMON);
     248        TASSERT(rc == EOK);
     249
     250        TPRINTF("waiting...");
     251        texit = TASK_EXIT_RUNNING; retval = 255;
     252        rc = task_wait(&wait, &texit, &retval);
     253        TPRINTF("done.\n");
     254        TASSERT(rc == EOK);
     255        TASSERT(task_wait_get(&wait) == TASK_WAIT_EXIT);
     256        TASSERT(retval == EOK);
     257        task_kill(tid); /* Terminate daemon */
     258        TPRINTF("waiting 2...");
     259        texit = TASK_EXIT_RUNNING; retval = 255;
     260        rc = task_wait(&wait, &texit, &retval);
     261        TPRINTF("done.\n");
     262        TASSERT(rc == EOK);
     263        TASSERT(task_wait_get(&wait) == 0);
     264        //TASSERT(texit == TASK_EXIT_UNEXPECTED); // TODO resolve this in taskman/kernel
     265        TPRINTF("OK\n");
     266        /* ---- */
     267
     268        TPRINTF("34 double wait in one\n");
     269
     270        task_wait_set(&wait, TASK_WAIT_BOTH);
     271        rc = dummy_task_spawn(&tid, &wait, STR_JOB_OK);
     272        TASSERT(rc == EOK);
     273
     274        TPRINTF("waiting...");
     275        texit = TASK_EXIT_RUNNING; retval = 255;
     276        rc = task_wait(&wait, &texit, &retval);
     277        TPRINTF("done.\n");
     278        TASSERT(rc == EOK);
     279        TASSERT(task_wait_get(&wait) == 0);
    203280        TASSERT(texit == TASK_EXIT_NORMAL);
    204281        TASSERT(retval == EOK);
  • uspace/lib/c/generic/task.c

    r55fe220 rd4ec49e  
    128128 *
    129129 * @return EOK on success, else error code.
     130 * @return TODO check this doesn't return EINVAL -- clash with task_wait
    130131 */
    131132static errno_t task_setup_wait(task_id_t id, task_wait_t *wait)
    132133{
    133134        assert(wait->flags);
     135        if (wait->flags & TASK_WAIT_BOTH) {
     136                wait->flags |= (TASK_WAIT_RETVAL | TASK_WAIT_EXIT);
     137        }
     138        wait->tid = id;
    134139        async_exch_t *exch = taskman_exchange_begin();
    135140        if (exch == NULL)
     
    391396 * @param retval Store return value of the task here.
    392397 *
    393  * @return EOK on success, else error code.
     398 * @return EOK on success
     399 * @return EINVAL on lost wait TODO other error codes
    394400 */
    395401errno_t task_wait(task_wait_t *wait, task_exit_t *texit, int *retval)
     
    397403        errno_t rc;
    398404        async_wait_for(wait->aid, &rc);
    399        
    400         if (rc == EOK) {
     405
     406        if (rc == EOK || rc == EINVAL) {
    401407                if (wait->flags & TASK_WAIT_EXIT && texit)
    402408                        *texit = ipc_get_arg1(wait->result);
    403409                if (wait->flags & TASK_WAIT_RETVAL && retval)
    404410                        *retval = ipc_get_arg2(wait->result);
     411               
     412        }
     413
     414        if (rc == EOK) {
     415                /* Is there another wait to be done? Wait for it! */
     416                int old_flags = wait->flags;
     417                wait->flags = ipc_get_arg3(wait->result);
     418                if (wait->flags != 0 && (old_flags & TASK_WAIT_BOTH)) {
     419                        rc = task_setup_wait(wait->tid, wait);
     420                }
     421        } else {
     422                wait->flags = 0;
    405423        }
    406424
  • uspace/lib/c/include/task.h

    r55fe220 rd4ec49e  
    4444#define TASK_WAIT_EXIT   0x1
    4545#define TASK_WAIT_RETVAL 0x2
     46#define TASK_WAIT_BOTH   0x4
    4647
    4748typedef struct {
     
    4950        ipc_call_t result;
    5051        aid_t aid;
     52        task_id_t tid;
    5153} task_wait_t;
    5254
     
    5456{
    5557        wait->flags = flags;
     58}
     59
     60static inline int task_wait_get(task_wait_t *wait)
     61{
     62        return wait->flags;
    5663}
    5764
     
    8491
    8592extern errno_t task_retval(int);
    86 //TODO
    87 //extern int task_exit(int);
    8893
    8994#endif
  • uspace/srv/taskman/main.c

    r55fe220 rd4ec49e  
    115115static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
    116116{
    117         printf("%s:%i\n", __func__, __LINE__);
     117        printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
    118118        int rc = task_set_retval(icall);
    119119        async_answer_0(iid, rc);
     
    122122static void task_exit_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    123123{
    124         printf("%s:%i\n", __func__, __LINE__);
    125124        // TODO design substitution for taskmon (monitoring)
    126125        task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
     126        printf("%s:%i from %llu/%i\n", __func__, __LINE__, id, (task_exit_t)arg);
    127127        task_terminated(id, (task_exit_t)arg);
    128128}
  • uspace/srv/taskman/task.c

    r55fe220 rd4ec49e  
    110110typedef struct {
    111111        link_t link;
    112         task_id_t id;         /**< Task ID. */
     112        task_id_t id;         /**< Task ID who we wait for. */
     113        task_id_t waiter_id;  /**< Task ID who waits. */
    113114        ipc_callid_t callid;  /**< Call ID waiting for the connection */
    114115        int flags;            /**< Wait flags */
     
    154155                }
    155156
     157                /*
     158                 * In current implementation you can wait for single retval,
     159                 * thus it can be never present in rest flags.
     160                 */
     161                int rest = (~notify_flags & pr->flags) & ~TASK_WAIT_RETVAL;
     162                rest &= ~TASK_WAIT_BOTH;
    156163                int match = notify_flags & pr->flags;
    157164                bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);
     165                printf("%s: %x; %x, %x\n", __func__, pr->flags, rest, match);
    158166
    159167                if (match == 0) {
     
    168176                        }
    169177                } else if (answer) {
    170                         /* Send both exit status and retval, caller should know
    171                          * what is valid */
    172                         async_answer_2(pr->callid, EOK, ht->exit, ht->retval);
     178                        if ((pr->flags & TASK_WAIT_BOTH) && match == TASK_WAIT_EXIT) {
     179                                async_answer_1(pr->callid, EINVAL, ht->exit);
     180                        } else {
     181                                /* Send both exit status and retval, caller
     182                                 * should know what is valid */
     183                                async_answer_3(pr->callid, EOK, ht->exit,
     184                                    ht->retval, rest);
     185                        }
     186
     187                        /* Pending wait has one more chance  */
     188                        if (rest && (pr->flags & TASK_WAIT_BOTH)) {
     189                                pr->flags = rest | TASK_WAIT_BOTH;
     190                                continue;
     191                        }
    173192                }
    174193
     
    183202void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)
    184203{
     204        assert(!(flags & TASK_WAIT_BOTH) ||
     205            ((flags & TASK_WAIT_RETVAL) && (flags & TASK_WAIT_EXIT)));
     206
    185207        fibril_rwlock_read_lock(&task_hash_table_lock);
    186208        ht_link_t *link = hash_table_find(&task_hash_table, &id);
     
    197219       
    198220        if (ht->exit != TASK_EXIT_RUNNING) {
    199                 task_exit_t texit = ht->exit;
    200                 async_answer_2(callid, EOK, texit, ht->retval);
     221                //TODO are flags BOTH processed correctly here?
     222                async_answer_3(callid, EOK, ht->exit, ht->retval, 0);
    201223                return;
    202224        }
    203225       
    204         /* Add to pending list */
    205         pending_wait_t *pr =
    206             (pending_wait_t *) malloc(sizeof(pending_wait_t));
    207         if (!pr) {
    208                 // TODO why IPC_CALLID_NOTIFICATION? explain!
    209                 if (!(callid & IPC_CALLID_NOTIFICATION))
    210                         async_answer_0(callid, ENOMEM);
    211                 return;
    212         }
    213        
    214         link_initialize(&pr->link);
    215         pr->id = id;
    216         pr->flags = flags;
    217         pr->callid = callid;
    218 
     226        /*
     227         * Add request to pending list or reuse existing item for a second
     228         * wait.
     229         */
     230        task_id_t waiter_id = call->in_task_id;
    219231        fibril_rwlock_write_lock(&pending_wait_lock);
    220         list_append(&pr->link, &pending_wait);
     232        pending_wait_t *pr = NULL;
     233        list_foreach(pending_wait, link, pending_wait_t, it) {
     234                if (it->id == id && it->waiter_id == waiter_id) {
     235                        pr = it;
     236                        break;
     237                }
     238        }
     239
     240        int rc = EOK;
     241        bool reuse = false;
     242        if (pr == NULL) {
     243                pr = malloc(sizeof(pending_wait_t));
     244                if (!pr) {
     245                        rc = ENOMEM;
     246                        goto finish;
     247                }
     248       
     249                link_initialize(&pr->link);
     250                pr->id = id;
     251                pr->waiter_id = waiter_id;
     252                pr->flags = flags;
     253                pr->callid = callid;
     254
     255                list_append(&pr->link, &pending_wait);
     256                rc = EOK;
     257        } else if (!(pr->flags & TASK_WAIT_BOTH)) {
     258                /*
     259                 * One task can wait for another task only once (per task, not
     260                 * fibril).
     261                 */
     262                rc = EEXISTS;
     263        } else {
     264                /*
     265                 * Reuse pending wait for the second time.
     266                 */
     267                pr->flags &= ~TASK_WAIT_BOTH; // TODO maybe new flags should be set?
     268                pr->callid = callid;
     269                reuse = true;
     270        }
     271        printf("%s: %llu: %x, %x, %i\n", __func__, pr->id, flags, pr->flags, reuse);
     272
     273finish:
    221274        fibril_rwlock_write_unlock(&pending_wait_lock);
     275        // TODO why IPC_CALLID_NOTIFICATION? explain!
     276        if (rc != EOK && !(callid & IPC_CALLID_NOTIFICATION))
     277                async_answer_0(callid, rc);
     278
    222279}
    223280
     
    249306
    250307        hash_table_insert(&task_hash_table, &ht->link);
     308        printf("%s: %llu\n", __func__, ht->id);
    251309       
    252310finish:
     
    260318        task_id_t id = call->in_task_id;
    261319       
    262         fibril_rwlock_read_lock(&task_hash_table_lock);
     320        fibril_rwlock_write_lock(&task_hash_table_lock);
    263321        ht_link_t *link = hash_table_find(&task_hash_table, &id);
    264322
     
    277335       
    278336finish:
    279         fibril_rwlock_read_unlock(&task_hash_table_lock);
     337        fibril_rwlock_write_unlock(&task_hash_table_lock);
    280338        return rc;
    281339}
     
    292350        hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    293351       
    294         if (ht->retval_type == RVAL_UNSET) {
     352        /*
     353         * If daemon returns a value and then fails/is killed, it's unexpected
     354         * termination.
     355         */
     356        if (ht->retval_type == RVAL_UNSET || texit == TASK_EXIT_UNEXPECTED) {
    295357                ht->exit = TASK_EXIT_UNEXPECTED;
    296358        } else {
Note: See TracChangeset for help on using the changeset viewer.