source: mainline/uspace/srv/taskman/main.c@ 241f1985

Last change on this file since 241f1985 was 241f1985, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Correcting failure from previous merge

The commits from Michal Koutný from the branch system-daemon
where built on a old version of Helenos. Because of this
many types and API functions have changed. This commit
upgrades the merge code

  • Property mode set to 100644
File size: 9.3 KB
RevLine 
[0a8f070]1/*
2 * Copyright (c) 2015 Michal Koutny
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[780c8ce]29/**
30 * Locking order:
31 * - task_hash_table_lock (task.c),
32 * - pending_wait_lock (event.c),
33 * - listeners_lock (event.c).
34 *
35 * @addtogroup taskman
36 * @{
37 */
38
[0a8f070]39#include <adt/prodcons.h>
40#include <assert.h>
41#include <async.h>
42#include <errno.h>
[012dd8e]43#include <fibril_synch.h>
[0a8f070]44#include <ipc/services.h>
45#include <ipc/taskman.h>
46#include <loader/loader.h>
[1be7bee]47#include <macros.h>
[0a8f070]48#include <ns.h>
49#include <stdio.h>
50#include <stdlib.h>
51
[035d7d8]52#include "event.h"
[1be7bee]53#include "task.h"
54#include "taskman.h"
[0a8f070]55
56
57typedef struct {
58 link_t link;
59 async_sess_t *sess;
60} sess_ref_t;
61
62static prodcons_t sess_queue;
63
[012dd8e]64/** We keep session to NS on our own in taskman */
65static async_sess_t *session_ns = NULL;
66
67static FIBRIL_MUTEX_INITIALIZE(session_ns_mtx);
68static FIBRIL_CONDVAR_INITIALIZE(session_ns_cv);
[0a8f070]69
70/*
71 * Static functions
72 */
[241f1985]73static void connect_to_loader(ipc_call_t *icall)
[0a8f070]74{
[241f1985]75 DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->task_id);
[2f44fafd]76 /* We don't accept the connection request, we forward it instead to
77 * freshly spawned loader. */
[241f1985]78 errno_t rc = loader_spawn("loader");
[0a8f070]79
80 if (rc != EOK) {
[241f1985]81 async_answer_0(icall, rc);
[0a8f070]82 return;
83 }
84
85 /* Wait until spawned task presents itself to us. */
86 link_t *link = prodcons_consume(&sess_queue);
87 sess_ref_t *sess_ref = list_get_instance(link, sess_ref_t, link);
88
89 /* Forward the connection request (strip interface arg). */
90 async_exch_t *exch = async_exchange_begin(sess_ref->sess);
[241f1985]91 rc = async_forward_1(icall, exch,
92 ipc_get_arg2(icall),
93 ipc_get_arg3(icall),
94 IPC_FF_NONE);
[0a8f070]95 async_exchange_end(exch);
96
[012dd8e]97 /* After forward we can dispose all session-related resources */
[2f44fafd]98 async_hangup(sess_ref->sess);
[0a8f070]99 free(sess_ref);
100
101 if (rc != EOK) {
[241f1985]102 async_answer_0(icall, rc);
[0a8f070]103 return;
104 }
105
106 /* Everything OK. */
107}
108
[241f1985]109static void connect_to_ns(ipc_call_t *icall)
[0a8f070]110{
[241f1985]111 DPRINTF("%s, %llu\n", __func__, icall->task_id);
[012dd8e]112
113 /* Wait until we know NS */
114 fibril_mutex_lock(&session_ns_mtx);
115 while (session_ns == NULL) {
116 fibril_condvar_wait(&session_ns_cv, &session_ns_mtx);
117 }
118 fibril_mutex_unlock(&session_ns_mtx);
119
120 /* Do not accept connection, forward it */
121 async_exch_t *exch = async_exchange_begin(session_ns);
[241f1985]122 errno_t rc = async_forward_0(icall, exch, 0, IPC_FF_NONE);
[0a8f070]123 async_exchange_end(exch);
124
125 if (rc != EOK) {
[241f1985]126 async_answer_0(icall, rc);
[0a8f070]127 return;
128 }
129}
130
[241f1985]131static void taskman_new_task(ipc_call_t *icall)
[012dd8e]132{
[241f1985]133 errno_t rc = task_intro(icall->task_id);
134 async_answer_0(icall, rc);
[012dd8e]135}
136
[241f1985]137static void taskman_i_am_ns(ipc_call_t *icall)
[012dd8e]138{
[241f1985]139 DPRINTF("%s, %llu\n", __func__, icall->task_id);
140 errno_t rc = EOK;
[012dd8e]141
142 fibril_mutex_lock(&session_ns_mtx);
143 if (session_ns != NULL) {
[241f1985]144 rc = EEXIST;
[012dd8e]145 goto finish;
146 }
147
148 /* Used only for connection forwarding -- atomic */
149 session_ns = async_callback_receive(EXCHANGE_ATOMIC);
150
151 if (session_ns == NULL) {
152 rc = ENOENT;
153 printf("%s: Cannot connect to NS\n", NAME);
154 }
155
[918ac9b]156 fibril_condvar_broadcast(&session_ns_cv);
[012dd8e]157finish:
158 fibril_mutex_unlock(&session_ns_mtx);
[241f1985]159 async_answer_0(icall, rc);
[012dd8e]160}
161
[241f1985]162static void taskman_ctl_wait(ipc_call_t *icall)
[1be7bee]163{
164 task_id_t id = (task_id_t)
[241f1985]165 MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
166 int flags = ipc_get_arg3(icall);
167 task_id_t waiter_id = icall->task_id;
[1be7bee]168
[241f1985]169 wait_for_task(id, flags, icall, waiter_id);
[1be7bee]170}
171
[241f1985]172static void taskman_ctl_retval(ipc_call_t *icall)
[1be7bee]173{
[241f1985]174 task_id_t sender = icall->task_id;
175 int retval = ipc_get_arg1(icall);
176 bool wait_for_exit = ipc_get_arg2(icall);
[780c8ce]177
[012dd8e]178 DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, sender, retval);
179
[241f1985]180 errno_t rc = task_set_retval(sender, retval, wait_for_exit);
181 async_answer_0(icall, rc);
[1be7bee]182}
183
[241f1985]184static void taskman_ctl_ev_callback(ipc_call_t *icall)
[b8341bc]185{
[241f1985]186 DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->task_id);
[012dd8e]187
[241f1985]188 bool past_events = ipc_get_arg1(icall);
[4ff66ae]189
[035d7d8]190 /* Atomic -- will be used for notifications only */
191 async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
192 if (sess == NULL) {
[241f1985]193 async_answer_0(icall, ENOMEM);
[035d7d8]194 return;
195 }
196
[241f1985]197 event_register_listener(icall->task_id, past_events, sess, icall);
[4667b5c]198}
199
[241f1985]200static void task_exit_event(ipc_call_t *icall, void *arg)
[62273d1]201{
[241f1985]202 task_id_t id = MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
203 exit_reason_t exit_reason = ipc_get_arg3(icall);
[012dd8e]204 DPRINTF("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
[5cd2290]205 task_terminated(id, exit_reason);
206}
207
[241f1985]208static void task_fault_event(ipc_call_t *icall, void *arg)
[5cd2290]209{
[241f1985]210 task_id_t id = MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
[012dd8e]211 DPRINTF("%s:%i from %llu\n", __func__, __LINE__, id);
[5cd2290]212 task_failed(id);
[62273d1]213}
214
[241f1985]215static void loader_callback(ipc_call_t *icall)
[0a8f070]216{
[241f1985]217 DPRINTF("%s:%i from %llu\n", __func__, __LINE__, icall->task_id);
[0a8f070]218 // TODO check that loader is expected, would probably discard prodcons
219 // scheme
220
221 /* Preallocate session container */
222 sess_ref_t *sess_ref = malloc(sizeof(sess_ref_t));
223 if (sess_ref == NULL) {
[241f1985]224 async_answer_0(icall, ENOMEM);
[0a8f070]225 }
226
227 /* Create callback connection */
228 sess_ref->sess = async_callback_receive_start(EXCHANGE_ATOMIC, icall);
229 if (sess_ref->sess == NULL) {
[241f1985]230 async_answer_0(icall, EINVAL);
[0a8f070]231 return;
232 }
[62273d1]233
[241f1985]234 async_answer_0(icall, EOK);
[0a8f070]235
[62273d1]236 /* Notify spawners */
[0a8f070]237 link_initialize(&sess_ref->link);
238 prodcons_produce(&sess_queue, &sess_ref->link);
239}
240
[241f1985]241static bool handle_call(ipc_call_t *icall)
[0a8f070]242{
[241f1985]243 switch (ipc_get_imethod(icall)) {
[012dd8e]244 case TASKMAN_NEW_TASK:
[241f1985]245 taskman_new_task(icall);
[0a8f070]246 break;
[012dd8e]247 case TASKMAN_I_AM_NS:
[241f1985]248 taskman_i_am_ns(icall);
[0a8f070]249 break;
[012dd8e]250 case TASKMAN_WAIT:
[241f1985]251 taskman_ctl_wait(icall);
[012dd8e]252 break;
253 case TASKMAN_RETVAL:
[241f1985]254 taskman_ctl_retval(icall);
[012dd8e]255 break;
256 case TASKMAN_EVENT_CALLBACK:
[241f1985]257 taskman_ctl_ev_callback(icall);
[1be7bee]258 break;
[0a8f070]259 default:
[012dd8e]260 return false;
[0a8f070]261 }
[012dd8e]262 return true;
263}
264
[241f1985]265static bool handle_implicit_call(ipc_call_t *icall)
[012dd8e]266{
[4ff66ae]267 /*DPRINTF("%s:%i %i(%i) from %llu\n", __func__, __LINE__,
[012dd8e]268 IPC_GET_IMETHOD(*icall),
269 IPC_GET_ARG1(*icall),
[4ff66ae]270 icall->in_task_id);*/
[012dd8e]271
[241f1985]272 if (ipc_get_imethod(icall) < IPC_FIRST_USER_METHOD) {
273 switch (ipc_get_arg1(icall)) {
[012dd8e]274 case TASKMAN_CONNECT_TO_NS:
[241f1985]275 connect_to_ns(icall);
[012dd8e]276 break;
277 case TASKMAN_CONNECT_TO_LOADER:
[241f1985]278 connect_to_loader(icall);
[012dd8e]279 break;
280 case TASKMAN_LOADER_CALLBACK:
[241f1985]281 loader_callback(icall);
[012dd8e]282 break;
283 default:
284 return false;
285
286 }
287 } else {
[241f1985]288 return handle_call(icall);
[012dd8e]289 }
290
291 return true;
[0a8f070]292}
293
[241f1985]294static void implicit_connection(ipc_call_t *icall, void *arg)
[0a8f070]295{
[241f1985]296 if (!handle_implicit_call(icall)) {
297 async_answer_0(icall, ENOTSUP);
[012dd8e]298 return;
299 }
300
301 while (true) {
302 ipc_call_t call;
303
[241f1985]304 if (!async_get_call(&call) || !ipc_get_imethod(&call)) {
[012dd8e]305 /* Client disconnected */
306 break;
307 }
308
[241f1985]309 if (!handle_implicit_call(&call)) {
310 async_answer_0(icall, ENOTSUP);
[012dd8e]311 break;
312 }
313 }
314}
315
[241f1985]316static void taskman_connection(ipc_call_t *icall, void *arg)
[012dd8e]317{
318 /*
319 * We don't expect (yet) clients to connect, having this function is
320 * just to adapt to async framework that creates new connection for
321 * each IPC_M_CONNECT_ME_TO.
322 * In this case those are to be forwarded, so don't continue
323 * "listening" on such connections.
324 */
[241f1985]325 if (!handle_implicit_call(icall)) {
326 /* If cannot handle connection request, give up trying */
327 async_answer_0(icall, EHANGUP);
[012dd8e]328 return;
[0a8f070]329 }
330}
331
332
[012dd8e]333
[0a8f070]334int main(int argc, char *argv[])
335{
336 printf(NAME ": HelenOS task manager\n");
337
[62273d1]338 /* Initialization */
[0a8f070]339 prodcons_initialize(&sess_queue);
[241f1985]340 errno_t rc = tasks_init();
[1be7bee]341 if (rc != EOK) {
342 return rc;
343 }
[035d7d8]344 rc = event_init();
345 if (rc != EOK) {
346 return rc;
347 }
[0a8f070]348
[5cd2290]349 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
[62273d1]350 if (rc != EOK) {
[012dd8e]351 printf(NAME ": Cannot register for exit events (%i).\n", rc);
[62273d1]352 return rc;
353 }
354
[5cd2290]355 rc = async_event_subscribe(EVENT_FAULT, task_fault_event, NULL);
[62273d1]356 if (rc != EOK) {
[012dd8e]357 printf(NAME ": Cannot register for fault events (%i).\n", rc);
[62273d1]358 return rc;
359 }
[012dd8e]360
361 task_id_t self_id = task_get_id();
362 rc = task_intro(self_id);
[0a8f070]363 if (rc != EOK) {
[012dd8e]364 printf(NAME ": Cannot register self as task (%i).\n", rc);
[0a8f070]365 }
366
367 /* Start sysman server */
368 async_set_implicit_connection(implicit_connection);
[241f1985]369 async_set_fallback_port_handler(taskman_connection, NULL);
[0a8f070]370
371 printf(NAME ": Accepting connections\n");
[012dd8e]372 (void)task_set_retval(self_id, EOK, false);
[0a8f070]373 async_manager();
374
375 /* not reached */
376 return 0;
377}
[780c8ce]378
379/**
380 * @}
381 */
Note: See TracBrowser for help on using the repository browser.