source: mainline/uspace/srv/taskman/main.c@ 13b4504

Last change on this file since 13b4504 was 3529f148, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Adding types task_wait_flag_t and ipc_start_flag_t which replaces makros

  • Property mode set to 100644
File size: 9.0 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 */
[16d748ee]38#include <abi/ipc/methods.h>
[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
56typedef struct {
57 link_t link;
58 async_sess_t *sess;
59} sess_ref_t;
60
61static prodcons_t sess_queue;
62
[012dd8e]63/** We keep session to NS on our own in taskman */
64static async_sess_t *session_ns = NULL;
65
66static FIBRIL_MUTEX_INITIALIZE(session_ns_mtx);
67static FIBRIL_CONDVAR_INITIALIZE(session_ns_cv);
[0a8f070]68
69/*
70 * Static functions
71 */
[241f1985]72static void connect_to_loader(ipc_call_t *icall)
[0a8f070]73{
[66b1075]74 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[102f641]75 /*
76 * We don't accept the connection request, we forward it instead to
77 * freshly spawned loader.
78 */
[241f1985]79 errno_t rc = loader_spawn("loader");
[102f641]80
[0a8f070]81 if (rc != EOK) {
[241f1985]82 async_answer_0(icall, rc);
[0a8f070]83 return;
84 }
[102f641]85
[0a8f070]86 /* Wait until spawned task presents itself to us. */
87 link_t *link = prodcons_consume(&sess_queue);
88 sess_ref_t *sess_ref = list_get_instance(link, sess_ref_t, link);
89
90 /* Forward the connection request (strip interface arg). */
91 async_exch_t *exch = async_exchange_begin(sess_ref->sess);
[241f1985]92 rc = async_forward_1(icall, exch,
93 ipc_get_arg2(icall),
94 ipc_get_arg3(icall),
95 IPC_FF_NONE);
[0a8f070]96 async_exchange_end(exch);
97
[012dd8e]98 /* After forward we can dispose all session-related resources */
[3529f148]99 //async_hangup(sess_ref->sess);
[0a8f070]100 free(sess_ref);
101
102 if (rc != EOK) {
[241f1985]103 async_answer_0(icall, rc);
[0a8f070]104 return;
105 }
106
107 /* Everything OK. */
108}
109
[241f1985]110static void connect_to_ns(ipc_call_t *icall)
[0a8f070]111{
[66b1075]112 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[012dd8e]113
114 /* Wait until we know NS */
115 fibril_mutex_lock(&session_ns_mtx);
116 while (session_ns == NULL) {
117 fibril_condvar_wait(&session_ns_cv, &session_ns_mtx);
118 }
119 fibril_mutex_unlock(&session_ns_mtx);
120
121 /* Do not accept connection, forward it */
122 async_exch_t *exch = async_exchange_begin(session_ns);
[241f1985]123 errno_t rc = async_forward_0(icall, exch, 0, IPC_FF_NONE);
[0a8f070]124 async_exchange_end(exch);
125
[16d748ee]126 if (rc != EOK)
[241f1985]127 async_answer_0(icall, rc);
[0a8f070]128}
129
[241f1985]130static void taskman_new_task(ipc_call_t *icall)
[012dd8e]131{
[66b1075]132 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[241f1985]133 errno_t rc = task_intro(icall->task_id);
[16d748ee]134 if (rc == EOK) {
135 async_accept_0(icall);
136 } else {
137 async_answer_0(icall, rc);
138 }
[012dd8e]139}
140
[241f1985]141static void taskman_i_am_ns(ipc_call_t *icall)
[012dd8e]142{
[66b1075]143 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[241f1985]144 errno_t rc = EOK;
[012dd8e]145
146 fibril_mutex_lock(&session_ns_mtx);
147 if (session_ns != NULL) {
[241f1985]148 rc = EEXIST;
[012dd8e]149 goto finish;
150 }
151
152 /* Used only for connection forwarding -- atomic */
153 session_ns = async_callback_receive(EXCHANGE_ATOMIC);
[102f641]154
[012dd8e]155 if (session_ns == NULL) {
156 rc = ENOENT;
157 printf("%s: Cannot connect to NS\n", NAME);
158 }
159
[918ac9b]160 fibril_condvar_broadcast(&session_ns_cv);
[012dd8e]161finish:
162 fibril_mutex_unlock(&session_ns_mtx);
[16d748ee]163
164 if (rc == EOK) {
165 async_accept_0(icall);
166 } else {
167 async_answer_0(icall, rc);
168 }
[012dd8e]169}
170
[241f1985]171static void taskman_ctl_wait(ipc_call_t *icall)
[1be7bee]172{
173 task_id_t id = (task_id_t)
[241f1985]174 MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
175 int flags = ipc_get_arg3(icall);
176 task_id_t waiter_id = icall->task_id;
[1be7bee]177
[241f1985]178 wait_for_task(id, flags, icall, waiter_id);
[1be7bee]179}
180
[241f1985]181static void taskman_ctl_retval(ipc_call_t *icall)
[1be7bee]182{
[241f1985]183 task_id_t sender = icall->task_id;
184 int retval = ipc_get_arg1(icall);
185 bool wait_for_exit = ipc_get_arg2(icall);
[780c8ce]186
[66b1075]187 DPRINTF("%s:%d from %" PRIu64 "/%i\n", __func__, __LINE__, sender, retval);
[012dd8e]188
[241f1985]189 errno_t rc = task_set_retval(sender, retval, wait_for_exit);
190 async_answer_0(icall, rc);
[1be7bee]191}
192
[241f1985]193static void taskman_ctl_ev_callback(ipc_call_t *icall)
[b8341bc]194{
[66b1075]195 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[012dd8e]196
[241f1985]197 bool past_events = ipc_get_arg1(icall);
[4ff66ae]198
[035d7d8]199 /* Atomic -- will be used for notifications only */
200 async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
201 if (sess == NULL) {
[241f1985]202 async_answer_0(icall, ENOMEM);
[035d7d8]203 return;
204 }
205
[241f1985]206 event_register_listener(icall->task_id, past_events, sess, icall);
[4667b5c]207}
208
[241f1985]209static void task_exit_event(ipc_call_t *icall, void *arg)
[62273d1]210{
[241f1985]211 task_id_t id = MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
212 exit_reason_t exit_reason = ipc_get_arg3(icall);
[66b1075]213 DPRINTF("%s:%d from %" PRIu64 "/%i\n", __func__, __LINE__, id, exit_reason);
[5cd2290]214 task_terminated(id, exit_reason);
215}
216
[241f1985]217static void task_fault_event(ipc_call_t *icall, void *arg)
[5cd2290]218{
[241f1985]219 task_id_t id = MERGE_LOUP32(ipc_get_arg1(icall), ipc_get_arg2(icall));
[66b1075]220 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, id);
[5cd2290]221 task_failed(id);
[62273d1]222}
223
[b2f05e2]224static void taskman_i_am_loader(ipc_call_t *icall)
[0a8f070]225{
[66b1075]226 DPRINTF("%s:%d from %" PRIu64 "\n", __func__, __LINE__, icall->task_id);
[0a8f070]227 // TODO check that loader is expected, would probably discard prodcons
228 // scheme
[102f641]229
[0a8f070]230 /* Preallocate session container */
231 sess_ref_t *sess_ref = malloc(sizeof(sess_ref_t));
232 if (sess_ref == NULL) {
[241f1985]233 async_answer_0(icall, ENOMEM);
[b09e0d7]234 return;
[0a8f070]235 }
236
237 /* Create callback connection */
[b2f05e2]238 sess_ref->sess = async_callback_receive(EXCHANGE_ATOMIC);
[0a8f070]239
[62273d1]240 /* Notify spawners */
[0a8f070]241 link_initialize(&sess_ref->link);
242 prodcons_produce(&sess_queue, &sess_ref->link);
243}
244
[16d748ee]245static void taskman_connection(ipc_call_t *icall, void *arg)
[012dd8e]246{
[b2f05e2]247 /* handle new incoming IPC_M_CONNECT_ME_TO calls */
248 switch (ipc_get_arg2(icall)) {
249 case TASKMAN_NEW_TASK:
250 taskman_new_task(icall);
251 break;
252 case TASKMAN_CONNECT_TO_NS:
253 connect_to_ns(icall);
254 break;
255 case TASKMAN_CONNECT_TO_LOADER:
256 connect_to_loader(icall);
257 break;
258 default:
259 DPRINTF("%s:%d from %" PRIu64 "/%" SCNuPTR "/%" SCNuPTR "/%" SCNuPTR "\n",
260 __func__, __LINE__,
261 icall->task_id, ipc_get_imethod(icall),
262 ipc_get_arg1(icall), ipc_get_arg2(icall));
263 async_answer_0(icall, ENOTSUP);
264 return;
[012dd8e]265 }
266
[16d748ee]267 /* handle accepted calls */
[012dd8e]268 while (true) {
269 ipc_call_t call;
270
[b2f05e2]271 if (!async_get_call(&call) || !ipc_get_imethod(&call)) {
[012dd8e]272 /* Client disconnected */
[66b1075]273 DPRINTF("%s:%d client disconnected\n", __func__, __LINE__);
[b2f05e2]274 break;
[012dd8e]275 }
276
[16d748ee]277 switch (ipc_get_imethod(&call)) {
278 case TASKMAN_I_AM_NS:
279 taskman_i_am_ns(&call);
[012dd8e]280 break;
[b2f05e2]281 case TASKMAN_I_AM_LOADER:
282 taskman_i_am_loader(&call);
283 break;
[16d748ee]284 case TASKMAN_WAIT:
285 taskman_ctl_wait(&call);
286 break;
287 case TASKMAN_RETVAL:
288 taskman_ctl_retval(&call);
289 break;
290 case TASKMAN_EVENT_CALLBACK:
291 taskman_ctl_ev_callback(&call);
292 break;
293 default:
[66b1075]294 DPRINTF("%s:%d from %" PRIu64 "/%" SCNuPTR "/%" SCNuPTR "/%" SCNuPTR "\n",
295 __func__, __LINE__,
296 call.task_id, ipc_get_imethod(&call),
297 ipc_get_arg1(&call), ipc_get_arg2(&call));
[16d748ee]298 async_answer_0(&call, ENOTSUP);
[012dd8e]299 }
300 }
301}
302
[0a8f070]303int main(int argc, char *argv[])
304{
305 printf(NAME ": HelenOS task manager\n");
306
[62273d1]307 /* Initialization */
[0a8f070]308 prodcons_initialize(&sess_queue);
[241f1985]309 errno_t rc = tasks_init();
[1be7bee]310 if (rc != EOK) {
311 return rc;
312 }
[035d7d8]313 rc = event_init();
314 if (rc != EOK) {
315 return rc;
316 }
[0a8f070]317
[5cd2290]318 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
[62273d1]319 if (rc != EOK) {
[012dd8e]320 printf(NAME ": Cannot register for exit events (%i).\n", rc);
[62273d1]321 return rc;
322 }
323
[5cd2290]324 rc = async_event_subscribe(EVENT_FAULT, task_fault_event, NULL);
[62273d1]325 if (rc != EOK) {
[012dd8e]326 printf(NAME ": Cannot register for fault events (%i).\n", rc);
[62273d1]327 return rc;
328 }
[102f641]329
[012dd8e]330 task_id_t self_id = task_get_id();
331 rc = task_intro(self_id);
[0a8f070]332 if (rc != EOK) {
[012dd8e]333 printf(NAME ": Cannot register self as task (%i).\n", rc);
[0a8f070]334 }
335
336 /* Start sysman server */
[241f1985]337 async_set_fallback_port_handler(taskman_connection, NULL);
[0a8f070]338
339 printf(NAME ": Accepting connections\n");
[012dd8e]340 (void)task_set_retval(self_id, EOK, false);
[0a8f070]341 async_manager();
342
343 /* not reached */
344 return 0;
345}
[780c8ce]346
347/**
348 * @}
349 */
Note: See TracBrowser for help on using the repository browser.