Changeset 2f44fafd in mainline


Ignore:
Timestamp:
2019-08-07T04:33:20Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
e0e7eba
Parents:
62273d1
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-10-12 21:58:23)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-07 04:33:20)
Message:

taskman: Implement task_wait API to pass all tests

  • different behavior for different wait flags
  • add locking to fibril code in taskman

Conflicts:

uspace/lib/c/generic/libc.c
uspace/lib/c/generic/task.c

Location:
uspace
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/libc.c

    r62273d1 r2f44fafd  
    190190        if (env_setup) {
    191191                __stdio_done();
    192                 task_retval(status);
     192                task_retval_internal(status, true);
    193193        }
    194194
  • uspace/lib/c/generic/private/task.h

    r62273d1 r2f44fafd  
    4040void __task_init(async_sess_t *);
    4141
     42int task_retval_internal(int, bool);
     43
    4244#endif
    4345
  • uspace/lib/c/generic/task.c

    r62273d1 r2f44fafd  
    131131static errno_t task_setup_wait(task_id_t id, task_wait_t *wait)
    132132{
     133        assert(wait->flags);
    133134        async_exch_t *exch = taskman_exchange_begin();
    134135        if (exch == NULL)
     
    435436}
    436437
    437 errno_t task_retval(int val)
     438errno_t task_retval_internal(int val, bool wait_for_exit)
    438439{
    439440        async_exch_t *exch = taskman_exchange_begin();
     
    441442                return EIO;
    442443
    443         int rc = (int) async_req_1_0(exch, TASKMAN_RETVAL, val);
     444        errno_t rc = (int) async_req_2_0(exch, TASKMAN_RETVAL, val, wait_for_exit);
    444445        taskman_exchange_end(exch);
    445446       
     
    447448}
    448449
     450errno_t task_retval(int val)
     451{
     452        return task_retval_internal(val, false);
     453}
     454
    449455
    450456void __task_init(async_sess_t *sess)
  • uspace/srv/taskman/main.c

    r62273d1 r2f44fafd  
    5858static void connect_to_loader(ipc_callid_t iid, ipc_call_t *icall)
    5959{
    60         //TODO explain why we don't explicitly accept connection request
    61         /* Spawn a loader. */
     60        /* We don't accept the connection request, we forward it instead to
     61         * freshly spawned loader. */
    6262        int rc = loader_spawn("loader");
    6363       
     
    7979        async_exchange_end(exch);
    8080
    81         // TODO leak? what happens with referenced sessions
     81        /* After forward we can dispose all session-related resources */
     82        async_hangup(sess_ref->sess);
    8283        free(sess_ref);
    8384
     
    153154static void control_connection(ipc_callid_t iid, ipc_call_t *icall)
    154155{
     156        /* TODO remove/redesign the workaround
     157         * Call task_intro here for boot-time tasks,
     158         * probably they should announce themselves explicitly
     159         * or taskman should detect them from kernel's list of tasks.
     160         */
     161        int rc = task_intro(icall, false);
     162
    155163        /* First, accept connection */
    156         async_answer_0(iid, EOK);
    157 
    158         // TODO register task to hash table
     164        async_answer_0(iid, rc);
     165
     166        if (rc != EOK) {
     167                return;
     168        }
     169
    159170        control_connection_loop();
    160171}
     
    174185        sess_ref->sess = async_callback_receive_start(EXCHANGE_ATOMIC, icall);
    175186        if (sess_ref->sess == NULL) {
    176                 //TODO different error code?
    177187                async_answer_0(iid, EINVAL);
    178188                return;
     
    180190
    181191        /* Remember task_id */
    182         int rc = task_id_intro(icall);
     192        int rc = task_intro(icall, true);
    183193
    184194        if (rc != EOK) {
     
    222232        case TASKMAN_LOADER_CALLBACK:
    223233                loader_callback(iid, icall);
    224                 // TODO register task to hashtable
    225234                control_connection_loop();
    226235                break;
     
    245254        }
    246255
    247         rc = async_event_subscribe(EVENT_EXIT, task_exit_event, (void *)EVENT_EXIT);
     256        rc = async_event_subscribe(EVENT_EXIT, task_exit_event, (void *)TASK_EXIT_NORMAL);
    248257        if (rc != EOK) {
    249258                printf("Cannot register for exit events (%i).\n", rc);
     
    251260        }
    252261
    253         rc = async_event_subscribe(EVENT_FAULT, task_exit_event, (void *)EVENT_FAULT);
     262        rc = async_event_subscribe(EVENT_FAULT, task_exit_event, (void *)TASK_EXIT_UNEXPECTED);
    254263        if (rc != EOK) {
    255264                printf("Cannot register for fault events (%i).\n", rc);
  • uspace/srv/taskman/task.c

    r62273d1 r2f44fafd  
    11/*
    2  * Copyright (c) 2009 Martin Decky
    3  * Copyright (c) 2009 Jiri Svoboda
    4  * Copyright (c) 2015 Michal Koutny
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
     2 * copyright (c) 2009 martin decky
     3 * copyright (c) 2009 jiri svoboda
     4 * copyright (c) 2015 michal koutny
     5 * all rights reserved.
     6 *
     7 * redistribution and use in source and binary forms, with or without
    88 * modification, are permitted provided that the following conditions
    99 * are met:
    1010 *
    11  * - Redistributions of source code must retain the above copyright
     11 * - redistributions of source code must retain the above copyright
    1212 *   notice, this list of conditions and the following disclaimer.
    13  * - Redistributions in binary form must reproduce the above copyright
     13 * - redistributions in binary form must reproduce the above copyright
    1414 *   notice, this list of conditions and the following disclaimer in the
    1515 *   documentation and/or other materials provided with the distribution.
    16  * - The name of the author may not be used to endorse or promote products
     16 * - the name of the author may not be used to endorse or promote products
    1717 *   derived from this software without specific prior written permission.
    1818 *
    19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     19 * this software is provided by the author ``as is'' and any express or
     20 * implied warranties, including, but not limited to, the implied warranties
     21 * of merchantability and fitness for a particular purpose are disclaimed.
     22 * in no event shall the author be liable for any direct, indirect,
     23 * incidental, special, exemplary, or consequential damages (including, but
     24 * not limited to, procurement of substitute goods or services; loss of use,
     25 * data, or profits; or business interruption) however caused and on any
     26 * theory of liability, whether in contract, strict liability, or tort
     27 * (including negligence or otherwise) arising in any way out of the use of
     28 * this software, even if advised of the possibility of such damage.
    2929 */
    3030
    31 /** @addtogroup taskman
     31/**
     32 * locking order:
     33 * - task_hash_table_lock,
     34 * - pending_wait_lock.
     35 *
     36 * @addtogroup taskman
    3237 * @{
    3338 */
     
    3742#include <async.h>
    3843#include <errno.h>
     44#include <fibril_synch.h>
    3945#include <macros.h>
    4046#include <malloc.h>
    4147#include <stdbool.h>
    4248#include <stdio.h>
     49#include <task.h>
    4350#include <types/task.h>
    4451
     
    4653#include "taskman.h"
    4754
    48 
    49 /** Task hash table item. */
     55/** what type of retval from the task we have */
     56typedef 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. */
    5063typedef struct {
    5164        ht_link_t link;
    5265       
    53         task_id_t id;    /**< Task ID. */
    54         task_exit_t exit;/**< Task is done. */
    55         bool have_rval;  /**< Task returned a value. */
    56         int retval;      /**< The return value. */
     66        task_id_t id;        /**< task id. */
     67        task_exit_t exit;    /**< task is done. */
     68        retval_t retval_type;  /**< task returned a value. */
     69        int retval;          /**< the return value. */
    5770} hashed_task_t;
    5871
     
    7588}
    7689
    77 /** Perform actions after removal of item from the hash table. */
     90/** perform actions after removal of item from the hash table. */
    7891static void task_remove(ht_link_t *item)
    7992{
     
    8194}
    8295
    83 /** Operations for task hash table. */
     96/** operations for task hash table. */
    8497static hash_table_ops_t task_hash_table_ops = {
    8598        .hash = task_hash,
     
    92105/** Task hash table structure. */
    93106static hash_table_t task_hash_table;
    94 
    95 typedef struct {
    96         ht_link_t link;
    97         sysarg_t in_phone_hash;  /**< Incoming phone hash. */
    98         task_id_t id;            /**< Task ID. */
    99 } p2i_entry_t;
    100 
    101 /* phone-to-id hash table operations */
    102 
    103 static size_t p2i_key_hash(void *key)
    104 {
    105         sysarg_t in_phone_hash = *(sysarg_t*)key;
    106         return in_phone_hash;
    107 }
    108 
    109 static size_t p2i_hash(const ht_link_t *item)
    110 {
    111         p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
    112         return entry->in_phone_hash;
    113 }
    114 
    115 static bool p2i_key_equal(void *key, const ht_link_t *item)
    116 {
    117         sysarg_t in_phone_hash = *(sysarg_t*)key;
    118         p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
    119        
    120         return (in_phone_hash == entry->in_phone_hash);
    121 }
    122 
    123 /** Perform actions after removal of item from the hash table.
    124  *
    125  * @param item Item that was removed from the hash table.
    126  *
    127  */
    128 static void p2i_remove(ht_link_t *item)
    129 {
    130         assert(item);
    131         free(hash_table_get_inst(item, p2i_entry_t, link));
    132 }
    133 
    134 /** Operations for task hash table. */
    135 static hash_table_ops_t p2i_ops = {
    136         .hash = p2i_hash,
    137         .key_hash = p2i_key_hash,
    138         .key_equal = p2i_key_equal,
    139         .equal = NULL,
    140         .remove_callback = p2i_remove
    141 };
    142 
    143 /** Map phone hash to task ID */
    144 static hash_table_t phone_to_id;
     107static FIBRIL_RWLOCK_INITIALIZE(task_hash_table_lock);
    145108
    146109/** Pending task wait structure. */
     
    149112        task_id_t id;         /**< Task ID. */
    150113        ipc_callid_t callid;  /**< Call ID waiting for the connection */
    151         int flags;            /**< Wait flags TODO */
     114        int flags;            /**< Wait flags */
    152115} pending_wait_t;
    153116
    154117static list_t pending_wait;
     118static FIBRIL_RWLOCK_INITIALIZE(pending_wait_lock);
    155119
    156120int task_init(void)
     
    161125        }
    162126       
    163         if (!hash_table_create(&phone_to_id, 0, 0, &p2i_ops)) {
    164                 printf(NAME ": No memory available for tasks\n");
    165                 return ENOMEM;
    166         }
    167        
    168127        list_initialize(&pending_wait);
    169128        return EOK;
    170129}
    171130
    172 /** Process pending wait requests */
     131/** Process pending wait requests
     132 *
     133 * Assumes task_hash_table_lock is hold (at least read)
     134 */
    173135void process_pending_wait(void)
    174136{
    175         task_exit_t texit;
    176        
     137        fibril_rwlock_write_lock(&pending_wait_lock);
    177138loop:
    178         // W lock
    179139        list_foreach(pending_wait, link, pending_wait_t, pr) {
    180                 // R lock task_hash_table
    181140                ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
    182                 // R unlock task_hash_table
    183141                if (!link)
    184142                        continue;
    185143               
    186144                hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    187                 if (ht->exit == TASK_EXIT_RUNNING)
    188                         continue;
    189                
    190                 if (!(pr->callid & IPC_CALLID_NOTIFICATION)) {
    191                         texit = ht->exit;
    192                         async_answer_2(pr->callid, EOK, texit,
    193                             ht->retval);
     145                int notify_flags = 0;
     146                if (ht->exit != TASK_EXIT_RUNNING) {
     147                        notify_flags |= TASK_WAIT_EXIT;
     148                        if (ht->retval_type == RVAL_SET_EXIT) {
     149                                notify_flags |= TASK_WAIT_RETVAL;
     150                        }
    194151                }
     152                if (ht->retval_type == RVAL_SET) {
     153                        notify_flags |= TASK_WAIT_RETVAL;
     154                }
     155
     156                int match = notify_flags & pr->flags;
     157                bool answer = !(pr->callid & IPC_CALLID_NOTIFICATION);
     158
     159                if (match == 0) {
     160                        if (notify_flags & TASK_WAIT_EXIT) {
     161                                /* Nothing to wait for anymore */
     162                                if (answer) {
     163                                        async_answer_0(pr->callid, EINVAL);
     164                                }
     165                        } else {
     166                                /* Maybe later */
     167                                continue;
     168                        }
     169                } 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);
     173                }
     174
    195175               
    196176                list_remove(&pr->link);
     
    198178                goto loop;
    199179        }
    200         // W unlock
     180        fibril_rwlock_write_unlock(&pending_wait_lock);
    201181}
    202182
    203183void wait_for_task(task_id_t id, int flags, ipc_callid_t callid, ipc_call_t *call)
    204184{
    205         // R lock
     185        fibril_rwlock_read_lock(&task_hash_table_lock);
    206186        ht_link_t *link = hash_table_find(&task_hash_table, &id);
    207         // R unlock
     187        fibril_rwlock_read_unlock(&task_hash_table_lock);
     188
    208189        hashed_task_t *ht = (link != NULL) ?
    209190            hash_table_get_inst(link, hashed_task_t, link) : NULL;
     
    235216        pr->flags = flags;
    236217        pr->callid = callid;
    237         // W lock
     218
     219        fibril_rwlock_write_lock(&pending_wait_lock);
    238220        list_append(&pr->link, &pending_wait);
    239         // W unlock
    240 }
    241 
    242 int task_id_intro(ipc_call_t *call)
    243 {
    244         // TODO think about task_id reuse and this
    245         // R lock
     221        fibril_rwlock_write_unlock(&pending_wait_lock);
     222}
     223
     224int task_intro(ipc_call_t *call, bool check_unique)
     225{
     226        int rc = EOK;
     227
     228        fibril_rwlock_write_lock(&task_hash_table_lock);
     229
    246230        ht_link_t *link = hash_table_find(&task_hash_table, &call->in_task_id);
    247         // R unlock
    248         if (link != NULL)
    249                 return EEXISTS;
     231        if (link != NULL) {
     232                rc = EEXISTS;
     233                goto finish;
     234        }
    250235       
    251236        hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
    252         if (ht == NULL)
    253                 return ENOMEM;
     237        if (ht == NULL) {
     238                rc = ENOMEM;
     239                goto finish;
     240        }
    254241
    255242        /*
     
    258245        ht->id = call->in_task_id;
    259246        ht->exit = TASK_EXIT_RUNNING;
    260         ht->have_rval = false;
     247        ht->retval_type = RVAL_UNSET;
    261248        ht->retval = -1;
    262         // W lock
     249
    263250        hash_table_insert(&task_hash_table, &ht->link);
    264         // W unlock
    265        
    266         return EOK;
     251       
     252finish:
     253        fibril_rwlock_write_unlock(&task_hash_table_lock);
     254        return rc;
    267255}
    268256
    269257int task_set_retval(ipc_call_t *call)
    270258{
     259        int rc = EOK;
    271260        task_id_t id = call->in_task_id;
    272261       
    273         // R lock
     262        fibril_rwlock_read_lock(&task_hash_table_lock);
    274263        ht_link_t *link = hash_table_find(&task_hash_table, &id);
    275         // R unlock
     264
    276265        hashed_task_t *ht = (link != NULL) ?
    277266            hash_table_get_inst(link, hashed_task_t, link) : NULL;
    278267       
    279         if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING))
    280                 return EINVAL;
    281        
    282         // TODO process additional flag to retval
    283         ht->have_rval = true;
     268        if ((ht == NULL) || (ht->exit != TASK_EXIT_RUNNING)) {
     269                rc = EINVAL;
     270                goto finish;
     271        }
     272       
    284273        ht->retval = IPC_GET_ARG1(*call);
     274        ht->retval_type = IPC_GET_ARG2(*call) ? RVAL_SET_EXIT : RVAL_SET;
    285275       
    286276        process_pending_wait();
    287277       
    288         return EOK;
     278finish:
     279        fibril_rwlock_read_unlock(&task_hash_table_lock);
     280        return rc;
    289281}
    290282
     
    292284{
    293285        /* Mark task as finished. */
    294         // R lock
     286        fibril_rwlock_write_lock(&task_hash_table_lock);
    295287        ht_link_t *link = hash_table_find(&task_hash_table, &id);
    296         // R unlock
    297         if (link == NULL)
    298                 return;
     288        if (link == NULL) {
     289                goto finish;
     290        }
    299291
    300292        hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
    301293       
    302         ht->exit = texit;
     294        if (ht->retval_type == RVAL_UNSET) {
     295                ht->exit = TASK_EXIT_UNEXPECTED;
     296        } else {
     297                ht->exit = texit;
     298        }
    303299        process_pending_wait();
    304300
    305         // W lock
    306301        hash_table_remove_item(&task_hash_table, &ht->link);
    307         // W unlock
     302finish:
     303        fibril_rwlock_write_unlock(&task_hash_table_lock);
    308304}
    309305
  • uspace/srv/taskman/task.h

    r62273d1 r2f44fafd  
    4444extern int task_set_retval(ipc_call_t *);
    4545
    46 extern int task_id_intro(ipc_call_t *);
     46extern int task_intro(ipc_call_t *, bool);
    4747extern void task_terminated(task_id_t, task_exit_t);
    4848
Note: See TracChangeset for help on using the changeset viewer.