Changeset 012dd8e in mainline for uspace/srv/taskman/main.c


Ignore:
Timestamp:
2019-08-07T09:15:30Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
e8747bd8
Parents:
780c8ce
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-11-01 00:08:04)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-07 09:15:30)
Message:

taskman: Handle INIT_TASKS as tasks spawned by loader

  • everyone is connected to its spawner, except for INIT_TASKS, they are connected to taskman (first binary)
  • taskman is now aware even of INIT_TASKS and taskman itself
  • refactored taskman handshake — NS session is created lazily
  • refactored async.c with usage of create_session
  • changed EINVAL to EINTR on lost waits
  • removed TODOs from taskman and related libc TODOs

Conflicts:

abi/include/abi/ipc/methods.h
boot/Makefile.common
uspace/lib/c/generic/async.c
uspace/lib/c/generic/libc.c
uspace/lib/c/generic/loader.c
uspace/lib/c/generic/ns.c
uspace/lib/c/generic/private/async.h
uspace/lib/c/generic/private/taskman.h
uspace/lib/c/generic/task.c
uspace/lib/c/include/async.h
uspace/lib/c/include/task.h
uspace/srv/loader/main.c
uspace/srv/ns/ns.c

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/taskman/main.c

    r780c8ce r012dd8e  
    4141#include <async.h>
    4242#include <errno.h>
     43#include <fibril_synch.h>
    4344#include <ipc/services.h>
    4445#include <ipc/taskman.h>
     
    5354#include "taskman.h"
    5455
    55 //TODO move to appropriate header file
    56 extern async_sess_t *session_primary;
     56//#define DPRINTF(...) printf(__VA_ARGS__)
     57#define DPRINTF(...) /* empty */
    5758
    5859typedef struct {
     
    6364static prodcons_t sess_queue;
    6465
     66/** We keep session to NS on our own in taskman */
     67static async_sess_t *session_ns = NULL;
     68
     69static FIBRIL_MUTEX_INITIALIZE(session_ns_mtx);
     70static FIBRIL_CONDVAR_INITIALIZE(session_ns_cv);
    6571
    6672/*
     
    6975static void connect_to_loader(ipc_callid_t iid, ipc_call_t *icall)
    7076{
     77        DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
    7178        /* We don't accept the connection request, we forward it instead to
    7279         * freshly spawned loader. */
     
    7481       
    7582        if (rc != EOK) {
    76                 printf(NAME ": %s -> %i\n", __func__, rc);
    7783                async_answer_0(iid, rc);
    7884                return;
     
    9197        async_exchange_end(exch);
    9298
    93         /* After forward we can dispose all session-related resources
    94          * TODO later could be recycled for notification API
    95          */
     99        /* After forward we can dispose all session-related resources */
    96100        async_hangup(sess_ref->sess);
    97101        free(sess_ref);
     
    105109}
    106110
    107 static void loader_to_ns(ipc_callid_t iid, ipc_call_t *icall)
    108 {
    109         /* Do no accept connection request, forward it instead. */
    110         async_exch_t *exch = async_exchange_begin(session_primary);
     111static void connect_to_ns(ipc_callid_t iid, ipc_call_t *icall)
     112{
     113        DPRINTF("%s, %llu\n", __func__, icall->in_task_id);
     114
     115        /* Wait until we know NS */
     116        fibril_mutex_lock(&session_ns_mtx);
     117        while (session_ns == NULL) {
     118                fibril_condvar_wait(&session_ns_cv, &session_ns_mtx);
     119        }
     120        fibril_mutex_unlock(&session_ns_mtx);
     121
     122        /* Do not accept connection, forward it */
     123        async_exch_t *exch = async_exchange_begin(session_ns);
    111124        int rc = async_forward_fast(iid, exch, 0, 0, 0, IPC_FF_NONE);
    112125        async_exchange_end(exch);
     
    116129                return;
    117130        }
     131}
     132
     133static void taskman_new_task(ipc_callid_t iid, ipc_call_t *icall)
     134{
     135        int rc = task_intro(icall->in_task_id);
     136        async_answer_0(iid, rc);
     137}
     138
     139static void taskman_i_am_ns(ipc_callid_t iid, ipc_call_t *icall)
     140{
     141        DPRINTF("%s, %llu\n", __func__, icall->in_task_id);
     142        int rc = EOK;
     143
     144        fibril_mutex_lock(&session_ns_mtx);
     145        if (session_ns != NULL) {
     146                rc = EEXISTS;
     147                goto finish;
     148        }
     149
     150        /* Used only for connection forwarding -- atomic */
     151        session_ns = async_callback_receive(EXCHANGE_ATOMIC);
     152       
     153        if (session_ns == NULL) {
     154                rc = ENOENT;
     155                printf("%s: Cannot connect to NS\n", NAME);
     156        }
     157
     158        fibril_condvar_signal(&session_ns_cv);
     159finish:
     160        fibril_mutex_unlock(&session_ns_mtx);
     161        async_answer_0(iid, rc);
    118162}
    119163
     
    130174static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
    131175{
    132         printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
    133176        task_id_t sender = icall->in_task_id;
    134177        int retval = IPC_GET_ARG1(*icall);
    135178        bool wait_for_exit = IPC_GET_ARG2(*icall);
    136179
     180        DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, sender, retval);
     181
    137182        int rc = task_set_retval(sender, retval, wait_for_exit);
    138183        async_answer_0(iid, rc);
     
    141186static void taskman_ctl_ev_callback(ipc_callid_t iid, ipc_call_t *icall)
    142187{
    143         printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
     188        DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
     189
    144190        /* Atomic -- will be used for notifications only */
    145191        async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
     
    157203        task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
    158204        exit_reason_t exit_reason = IPC_GET_ARG3(*icall);
    159         printf("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
     205        DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
    160206        task_terminated(id, exit_reason);
    161207}
     
    164210{
    165211        task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
    166         printf("%s:%i from %llu\n", __func__, __LINE__, id);
     212        DPRINTF("%s:%i from %llu\n", __func__, __LINE__, id);
    167213        task_failed(id);
    168214}
    169215
    170 static void control_connection_loop(void)
    171 {
    172         while (true) {
    173                 ipc_call_t call;
    174                 ipc_callid_t callid = async_get_call(&call);
    175 
    176                 if (!IPC_GET_IMETHOD(call)) {
    177                         /* Client disconnected */
    178                         break;
    179                 }
    180 
    181                 switch (IPC_GET_IMETHOD(call)) {
    182                 case TASKMAN_WAIT:
    183                         taskman_ctl_wait(callid, &call);
    184                         break;
    185                 case TASKMAN_RETVAL:
    186                         taskman_ctl_retval(callid, &call);
    187                         break;
    188                 case TASKMAN_EVENT_CALLBACK:
    189                         taskman_ctl_ev_callback(callid, &call);
    190                         break;
    191                 default:
    192                         async_answer_0(callid, ENOENT);
    193                 }
    194         }
    195 }
    196 
    197 static void control_connection(ipc_callid_t iid, ipc_call_t *icall)
    198 {
    199         /* TODO remove/redesign the workaround
    200          * Call task_intro here for boot-time tasks,
    201          * probably they should announce themselves explicitly
    202          * or taskman should detect them from kernel's list of tasks.
    203          */
    204         int rc = task_intro(icall, false);
    205 
    206         /* First, accept connection */
    207         async_answer_0(iid, rc);
    208 
    209         if (rc != EOK) {
    210                 return;
    211         }
    212 
    213         control_connection_loop();
    214 }
    215 
    216216static void loader_callback(ipc_callid_t iid, ipc_call_t *icall)
    217217{
     218        DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
    218219        // TODO check that loader is expected, would probably discard prodcons
    219220        //      scheme
     
    232233        }
    233234
    234         /* Remember task_id */
    235         int rc = task_intro(icall, true);
    236 
    237         if (rc != EOK) {
    238                 async_answer_0(iid, rc);
    239                 free(sess_ref);
    240                 return;
    241         }
    242235        async_answer_0(iid, EOK);
    243236
     
    247240}
    248241
     242static bool handle_call(ipc_callid_t iid, ipc_call_t *icall)
     243{
     244        switch (IPC_GET_IMETHOD(*icall)) {
     245        case TASKMAN_NEW_TASK:
     246                taskman_new_task(iid, icall);
     247                break;
     248        case TASKMAN_I_AM_NS:
     249                taskman_i_am_ns(iid, icall);
     250                break;
     251        case TASKMAN_WAIT:
     252                taskman_ctl_wait(iid, icall);
     253                break;
     254        case TASKMAN_RETVAL:
     255                taskman_ctl_retval(iid, icall);
     256                break;
     257        case TASKMAN_EVENT_CALLBACK:
     258                taskman_ctl_ev_callback(iid, icall);
     259                break;
     260        default:
     261                return false;
     262        }
     263        return true;
     264}
     265
     266static bool handle_implicit_call(ipc_callid_t iid, ipc_call_t *icall)
     267{
     268        DPRINTF("%s:%i %i(%i) from %llu\n", __func__, __LINE__,
     269            IPC_GET_IMETHOD(*icall),
     270            IPC_GET_ARG1(*icall),
     271            icall->in_task_id);
     272
     273        if (IPC_GET_IMETHOD(*icall) < IPC_FIRST_USER_METHOD) {
     274                switch (IPC_GET_ARG1(*icall)) {
     275                case TASKMAN_CONNECT_TO_NS:
     276                        connect_to_ns(iid, icall);
     277                        break;
     278                case TASKMAN_CONNECT_TO_LOADER:
     279                        connect_to_loader(iid, icall);
     280                        break;
     281                case TASKMAN_LOADER_CALLBACK:
     282                        loader_callback(iid, icall);
     283                        break;
     284                default:
     285                        return false;
     286
     287                }
     288        } else {
     289                return handle_call(iid, icall);
     290        }
     291
     292        return true;
     293}
     294
     295static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     296{
     297        if (!handle_implicit_call(iid, icall)) {
     298                async_answer_0(iid, ENOTSUP);
     299                return;
     300        }
     301
     302        while (true) {
     303                ipc_call_t call;
     304                ipc_callid_t callid = async_get_call(&call);
     305
     306                if (!IPC_GET_IMETHOD(call)) {
     307                        /* Client disconnected */
     308                        break;
     309                }
     310
     311                if (!handle_implicit_call(callid, &call)) {
     312                        async_answer_0(callid, ENOTSUP);
     313                        break;
     314                }
     315        }
     316}
     317
    249318static void taskman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    250319{
    251         taskman_interface_t iface = IPC_GET_ARG1(*icall);
    252         switch (iface) {
    253         case TASKMAN_CONNECT_TO_LOADER:
    254                 connect_to_loader(iid, icall);
    255                 break;
    256         case TASKMAN_LOADER_TO_NS:
    257                 loader_to_ns(iid, icall);
    258                 break;
    259         case TASKMAN_CONTROL:
    260                 control_connection(iid, icall);
    261                 break;
    262         default:
    263                 /* Unknown interface */
    264                 async_answer_0(iid, ENOENT);
    265         }
    266 }
    267 
    268 static void implicit_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    269 {
    270         taskman_interface_t iface = IPC_GET_ARG1(*icall);
    271         switch (iface) {
    272         case TASKMAN_LOADER_CALLBACK:
    273                 loader_callback(iid, icall);
    274                 control_connection_loop();
    275                 break;
    276         default:
    277                 /* Unknown interface on implicit connection */
     320        /*
     321         * We don't expect (yet) clients to connect, having this function is
     322         * just to adapt to async framework that creates new connection for
     323         * each IPC_M_CONNECT_ME_TO.
     324         * In this case those are to be forwarded, so don't continue
     325         * "listening" on such connections.
     326         */
     327        if (!handle_implicit_call(iid, icall)) {
     328                /* If cannot handle connection requst, give up trying */
    278329                async_answer_0(iid, EHANGUP);
    279         }
    280 }
     330                return;
     331        }
     332}
     333
    281334
    282335
     
    298351        rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
    299352        if (rc != EOK) {
    300                 printf("Cannot register for exit events (%i).\n", rc);
     353                printf(NAME ": Cannot register for exit events (%i).\n", rc);
    301354                return rc;
    302355        }
     
    304357        rc = async_event_subscribe(EVENT_FAULT, task_fault_event, NULL);
    305358        if (rc != EOK) {
    306                 printf("Cannot register for fault events (%i).\n", rc);
     359                printf(NAME ": Cannot register for fault events (%i).\n", rc);
    307360                return rc;
    308361        }
    309 
    310         /* We're service too */
    311         rc = service_register(SERVICE_TASKMAN);
    312         if (rc != EOK) {
    313                 printf("Cannot register at naming service (%i).\n", rc);
    314                 return rc;
     362       
     363        task_id_t self_id = task_get_id();
     364        rc = task_intro(self_id);
     365        if (rc != EOK) {
     366                printf(NAME ": Cannot register self as task (%i).\n", rc);
    315367        }
    316368
    317369        /* Start sysman server */
     370        async_set_implicit_connection(implicit_connection);
    318371        async_set_client_connection(taskman_connection);
    319         async_set_implicit_connection(implicit_connection);
    320372
    321373        printf(NAME ": Accepting connections\n");
    322         //TODO task_retval(EOK);
     374        (void)task_set_retval(self_id, EOK, false);
    323375        async_manager();
    324376
Note: See TracChangeset for help on using the changeset viewer.