source: mainline/uspace/srv/taskman/main.c@ 780c8ce

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

taskman: Light streamlining (removing TODOs)

  • Low work attitude today :-(
  • Property mode set to 100644
File size: 8.3 KB
Line 
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
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
39#include <adt/prodcons.h>
40#include <assert.h>
41#include <async.h>
42#include <errno.h>
43#include <ipc/services.h>
44#include <ipc/taskman.h>
45#include <loader/loader.h>
46#include <macros.h>
47#include <ns.h>
48#include <stdio.h>
49#include <stdlib.h>
50
51#include "event.h"
52#include "task.h"
53#include "taskman.h"
54
55//TODO move to appropriate header file
56extern async_sess_t *session_primary;
57
58typedef struct {
59 link_t link;
60 async_sess_t *sess;
61} sess_ref_t;
62
63static prodcons_t sess_queue;
64
65
66/*
67 * Static functions
68 */
69static void connect_to_loader(ipc_callid_t iid, ipc_call_t *icall)
70{
71 /* We don't accept the connection request, we forward it instead to
72 * freshly spawned loader. */
73 int rc = loader_spawn("loader");
74
75 if (rc != EOK) {
76 printf(NAME ": %s -> %i\n", __func__, rc);
77 async_answer_0(iid, rc);
78 return;
79 }
80
81 /* Wait until spawned task presents itself to us. */
82 link_t *link = prodcons_consume(&sess_queue);
83 sess_ref_t *sess_ref = list_get_instance(link, sess_ref_t, link);
84
85 /* Forward the connection request (strip interface arg). */
86 async_exch_t *exch = async_exchange_begin(sess_ref->sess);
87 rc = async_forward_fast(iid, exch,
88 IPC_GET_ARG2(*icall),
89 IPC_GET_ARG3(*icall),
90 0, IPC_FF_NONE);
91 async_exchange_end(exch);
92
93 /* After forward we can dispose all session-related resources
94 * TODO later could be recycled for notification API
95 */
96 async_hangup(sess_ref->sess);
97 free(sess_ref);
98
99 if (rc != EOK) {
100 async_answer_0(iid, rc);
101 return;
102 }
103
104 /* Everything OK. */
105}
106
107static 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);
111 int rc = async_forward_fast(iid, exch, 0, 0, 0, IPC_FF_NONE);
112 async_exchange_end(exch);
113
114 if (rc != EOK) {
115 async_answer_0(iid, rc);
116 return;
117 }
118}
119
120static void taskman_ctl_wait(ipc_callid_t iid, ipc_call_t *icall)
121{
122 task_id_t id = (task_id_t)
123 MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
124 int flags = IPC_GET_ARG3(*icall);
125 task_id_t waiter_id = icall->in_task_id;
126
127 wait_for_task(id, flags, iid, waiter_id);
128}
129
130static void taskman_ctl_retval(ipc_callid_t iid, ipc_call_t *icall)
131{
132 printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
133 task_id_t sender = icall->in_task_id;
134 int retval = IPC_GET_ARG1(*icall);
135 bool wait_for_exit = IPC_GET_ARG2(*icall);
136
137 int rc = task_set_retval(sender, retval, wait_for_exit);
138 async_answer_0(iid, rc);
139}
140
141static void taskman_ctl_ev_callback(ipc_callid_t iid, ipc_call_t *icall)
142{
143 printf("%s:%i from %llu\n", __func__, __LINE__, icall->in_task_id);
144 /* Atomic -- will be used for notifications only */
145 async_sess_t *sess = async_callback_receive(EXCHANGE_ATOMIC);
146 if (sess == NULL) {
147 async_answer_0(iid, ENOMEM);
148 return;
149 }
150
151 int rc = event_register_listener(icall->in_task_id, sess);
152 async_answer_0(iid, rc);
153}
154
155static void task_exit_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
156{
157 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
158 exit_reason_t exit_reason = IPC_GET_ARG3(*icall);
159 printf("%s:%i from %llu/%i\n", __func__, __LINE__, id, exit_reason);
160 task_terminated(id, exit_reason);
161}
162
163static void task_fault_event(ipc_callid_t iid, ipc_call_t *icall, void *arg)
164{
165 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*icall), IPC_GET_ARG2(*icall));
166 printf("%s:%i from %llu\n", __func__, __LINE__, id);
167 task_failed(id);
168}
169
170static 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
197static 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
216static void loader_callback(ipc_callid_t iid, ipc_call_t *icall)
217{
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) {
224 async_answer_0(iid, ENOMEM);
225 }
226
227 /* Create callback connection */
228 sess_ref->sess = async_callback_receive_start(EXCHANGE_ATOMIC, icall);
229 if (sess_ref->sess == NULL) {
230 async_answer_0(iid, EINVAL);
231 return;
232 }
233
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 }
242 async_answer_0(iid, EOK);
243
244 /* Notify spawners */
245 link_initialize(&sess_ref->link);
246 prodcons_produce(&sess_queue, &sess_ref->link);
247}
248
249static void taskman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
250{
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
268static 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 */
278 async_answer_0(iid, EHANGUP);
279 }
280}
281
282
283int main(int argc, char *argv[])
284{
285 printf(NAME ": HelenOS task manager\n");
286
287 /* Initialization */
288 prodcons_initialize(&sess_queue);
289 int rc = task_init();
290 if (rc != EOK) {
291 return rc;
292 }
293 rc = event_init();
294 if (rc != EOK) {
295 return rc;
296 }
297
298 rc = async_event_subscribe(EVENT_EXIT, task_exit_event, NULL);
299 if (rc != EOK) {
300 printf("Cannot register for exit events (%i).\n", rc);
301 return rc;
302 }
303
304 rc = async_event_subscribe(EVENT_FAULT, task_fault_event, NULL);
305 if (rc != EOK) {
306 printf("Cannot register for fault events (%i).\n", rc);
307 return rc;
308 }
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;
315 }
316
317 /* Start sysman server */
318 async_set_client_connection(taskman_connection);
319 async_set_implicit_connection(implicit_connection);
320
321 printf(NAME ": Accepting connections\n");
322 //TODO task_retval(EOK);
323 async_manager();
324
325 /* not reached */
326 return 0;
327}
328
329/**
330 * @}
331 */
Note: See TracBrowser for help on using the repository browser.