Changeset d4ec49e in mainline for uspace/srv/taskman/task.c


Ignore:
Timestamp:
2019-08-07T05:25:59Z (6 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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.