source: mainline/uspace/srv/ns/ns.c@ d0a1d961

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d0a1d961 was 3636964, checked in by Martin Decky <martin@…>, 16 years ago

make klog more generic

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
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/** @addtogroup ns
30 * @{
31 */
32
33/**
34 * @file ns.c
35 * @brief Naming service for HelenOS IPC.
36 */
37
38
39#include <ipc/ipc.h>
40#include <ipc/ns.h>
41#include <ipc/services.h>
42#include <stdio.h>
43#include <bool.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <errno.h>
47#include <assert.h>
48#include <libadt/list.h>
49#include <libadt/hash_table.h>
50#include <sysinfo.h>
51#include <loader/loader.h>
52#include <ddi.h>
53#include <as.h>
54
55#define NAME "ns"
56
57#define NS_HASH_TABLE_CHAINS 20
58
59static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
60static void connect_to_service(ipcarg_t service, ipc_call_t *call,
61 ipc_callid_t callid);
62
63void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
64 ipc_callid_t callid);
65void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
66 ipc_callid_t callid);
67
68
69/* Static functions implementing NS hash table operations. */
70static hash_index_t ns_hash(unsigned long *key);
71static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item);
72static void ns_remove(link_t *item);
73
74/** Operations for NS hash table. */
75static hash_table_operations_t ns_hash_table_ops = {
76 .hash = ns_hash,
77 .compare = ns_compare,
78 .remove_callback = ns_remove
79};
80
81/** NS hash table structure. */
82static hash_table_t ns_hash_table;
83
84/** NS hash table item. */
85typedef struct {
86 link_t link;
87 ipcarg_t service; /**< Number of the service. */
88 ipcarg_t phone; /**< Phone registered with the service. */
89 ipcarg_t in_phone_hash; /**< Incoming phone hash. */
90} hashed_service_t;
91
92/** Pending connection structure. */
93typedef struct {
94 link_t link;
95 ipcarg_t service; /**< Number of the service. */
96 ipc_callid_t callid; /**< Call ID waiting for the connection */
97 ipcarg_t arg2; /**< Second argument */
98 ipcarg_t arg3; /**< Third argument */
99} pending_req_t;
100
101static link_t pending_req;
102
103/** Request for connection to a clonable service. */
104typedef struct {
105 link_t link;
106 ipcarg_t service;
107 ipc_call_t call;
108 ipc_callid_t callid;
109} cs_req_t;
110
111/** List of clonable-service connection requests. */
112static link_t cs_req;
113
114static void *clockaddr = NULL;
115static void *klogaddr = NULL;
116
117/** Return true if @a service is clonable. */
118static bool service_clonable(int service)
119{
120 return (service == SERVICE_LOAD);
121}
122
123static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr)
124{
125 if (ph_addr == NULL) {
126 ipc_answer_0(callid, ENOENT);
127 return;
128 }
129
130 if (*addr == NULL) {
131 *addr = as_get_mappable_page(pages * PAGE_SIZE);
132
133 if (*addr == NULL) {
134 ipc_answer_0(callid, ENOENT);
135 return;
136 }
137
138 if (physmem_map(ph_addr, *addr, pages,
139 AS_AREA_READ | AS_AREA_CACHEABLE) != 0) {
140 ipc_answer_0(callid, ENOENT);
141 return;
142 }
143 }
144
145 ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ);
146}
147
148/** Process pending connection requests */
149static void process_pending_req()
150{
151 link_t *cur;
152
153loop:
154 for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
155 pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
156
157 unsigned long keys[3] = {
158 pr->service,
159 0,
160 0
161 };
162
163 link_t *link = hash_table_find(&ns_hash_table, keys);
164 if (!link)
165 continue;
166
167 hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
168 ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
169 pr->arg2, pr->arg3, 0, IPC_FF_NONE);
170
171 if (!(pr->callid & IPC_CALLID_NOTIFICATION))
172 ipc_answer_0(pr->callid, retval);
173
174 list_remove(cur);
175 free(pr);
176 goto loop;
177 }
178}
179
180int main(int argc, char **argv)
181{
182 printf(NAME ": HelenOS IPC Naming Service\n");
183
184 if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3,
185 &ns_hash_table_ops)) {
186 printf(NAME ": No memory available for services\n");
187 return ENOMEM;
188 }
189
190 list_initialize(&pending_req);
191 list_initialize(&cs_req);
192
193 printf(NAME ": Accepting connections\n");
194 while (true) {
195 process_pending_req();
196
197 ipc_call_t call;
198 ipc_callid_t callid = ipc_wait_for_call(&call);
199 ipcarg_t retval;
200
201 switch (IPC_GET_METHOD(call)) {
202 case IPC_M_SHARE_IN:
203 switch (IPC_GET_ARG3(call)) {
204 case SERVICE_MEM_REALTIME:
205 get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr);
206 break;
207 case SERVICE_MEM_KLOG:
208 get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr);
209 break;
210 default:
211 ipc_answer_0(callid, ENOENT);
212 }
213 continue;
214 case IPC_M_PHONE_HUNGUP:
215 retval = EOK;
216 break;
217 case IPC_M_CONNECT_TO_ME:
218 /*
219 * Server requests service registration.
220 */
221 if (service_clonable(IPC_GET_ARG1(call))) {
222 register_clonable(IPC_GET_ARG1(call),
223 IPC_GET_ARG5(call), &call, callid);
224 continue;
225 } else {
226 retval = register_service(IPC_GET_ARG1(call),
227 IPC_GET_ARG5(call), &call);
228 }
229 break;
230 case IPC_M_CONNECT_ME_TO:
231 /*
232 * Client requests to be connected to a service.
233 */
234 if (service_clonable(IPC_GET_ARG1(call))) {
235 connect_to_clonable(IPC_GET_ARG1(call),
236 &call, callid);
237 continue;
238 } else {
239 connect_to_service(IPC_GET_ARG1(call), &call,
240 callid);
241 continue;
242 }
243 break;
244 default:
245 retval = ENOENT;
246 break;
247 }
248
249 if (!(callid & IPC_CALLID_NOTIFICATION))
250 ipc_answer_0(callid, retval);
251 }
252
253 /* Not reached */
254 return 0;
255}
256
257/** Register service.
258 *
259 * @param service Service to be registered.
260 * @param phone Phone to be used for connections to the service.
261 * @param call Pointer to call structure.
262 *
263 * @return Zero on success or a value from @ref errno.h.
264 *
265 */
266int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
267{
268 unsigned long keys[3] = {
269 service,
270 call->in_phone_hash,
271 0
272 };
273
274 if (hash_table_find(&ns_hash_table, keys))
275 return EEXISTS;
276
277 hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
278 if (!hs)
279 return ENOMEM;
280
281 link_initialize(&hs->link);
282 hs->service = service;
283 hs->phone = phone;
284 hs->in_phone_hash = call->in_phone_hash;
285 hash_table_insert(&ns_hash_table, keys, &hs->link);
286
287 return 0;
288}
289
290/** Connect client to service.
291 *
292 * @param service Service to be connected to.
293 * @param call Pointer to call structure.
294 * @param callid Call ID of the request.
295 *
296 * @return Zero on success or a value from @ref errno.h.
297 *
298 */
299void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
300{
301 ipcarg_t retval;
302 unsigned long keys[3] = {
303 service,
304 0,
305 0
306 };
307
308 link_t *link = hash_table_find(&ns_hash_table, keys);
309 if (!link) {
310 if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
311 /* Blocking connection, add to pending list */
312 pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
313 if (!pr) {
314 retval = ENOMEM;
315 goto out;
316 }
317
318 pr->service = service;
319 pr->callid = callid;
320 pr->arg2 = IPC_GET_ARG2(*call);
321 pr->arg3 = IPC_GET_ARG3(*call);
322 list_append(&pr->link, &pending_req);
323 return;
324 }
325 retval = ENOENT;
326 goto out;
327 }
328
329 hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
330 retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
331 IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
332out:
333 if (!(callid & IPC_CALLID_NOTIFICATION))
334 ipc_answer_0(callid, retval);
335}
336
337/** Register clonable service.
338 *
339 * @param service Service to be registered.
340 * @param phone Phone to be used for connections to the service.
341 * @param call Pointer to call structure.
342 *
343 */
344void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
345 ipc_callid_t callid)
346{
347 if (list_empty(&cs_req)) {
348 /* There was no pending connection request. */
349 printf(NAME ": Unexpected clonable server.\n");
350 ipc_answer_0(callid, EBUSY);
351 return;
352 }
353
354 cs_req_t *csr = list_get_instance(cs_req.next, cs_req_t, link);
355 list_remove(&csr->link);
356
357 /* Currently we can only handle a single type of clonable service. */
358 assert(csr->service == SERVICE_LOAD);
359
360 ipc_answer_0(callid, EOK);
361
362 int rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call),
363 IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE);
364
365 free(csr);
366 ipc_hangup(phone);
367}
368
369/** Connect client to clonable service.
370 *
371 * @param service Service to be connected to.
372 * @param call Pointer to call structure.
373 * @param callid Call ID of the request.
374 *
375 * @return Zero on success or a value from @ref errno.h.
376 *
377 */
378void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
379 ipc_callid_t callid)
380{
381 assert(service == SERVICE_LOAD);
382
383 cs_req_t *csr = malloc(sizeof(cs_req_t));
384 if (csr == NULL) {
385 ipc_answer_0(callid, ENOMEM);
386 return;
387 }
388
389 /* Spawn a loader. */
390 int rc = loader_spawn("loader");
391
392 if (rc < 0) {
393 free(csr);
394 ipc_answer_0(callid, rc);
395 return;
396 }
397
398 csr->service = service;
399 csr->call = *call;
400 csr->callid = callid;
401
402 /*
403 * We can forward the call only after the server we spawned connects
404 * to us. Meanwhile we might need to service more connection requests.
405 * Thus we store the call in a queue.
406 */
407 list_append(&csr->link, &cs_req);
408}
409
410/** Compute hash index into NS hash table.
411 *
412 * @param key Pointer keys. However, only the first key (i.e. service number)
413 * is used to compute the hash index.
414 *
415 * @return Hash index corresponding to key[0].
416 *
417 */
418hash_index_t ns_hash(unsigned long *key)
419{
420 assert(key);
421 return (*key % NS_HASH_TABLE_CHAINS);
422}
423
424/** Compare a key with hashed item.
425 *
426 * This compare function always ignores the third key.
427 * It exists only to make it possible to remove records
428 * originating from connection with key[1] in_phone_hash
429 * value. Note that this is close to being classified
430 * as a nasty hack.
431 *
432 * @param key Array of keys.
433 * @param keys Must be lesser or equal to 3.
434 * @param item Pointer to a hash table item.
435 *
436 * @return Non-zero if the key matches the item, zero otherwise.
437 *
438 */
439int ns_compare(unsigned long key[], hash_count_t keys, link_t *item)
440{
441 assert(key);
442 assert(keys <= 3);
443 assert(item);
444
445 hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
446
447 if (keys == 2)
448 return key[1] == hs->in_phone_hash;
449 else
450 return key[0] == hs->service;
451}
452
453/** Perform actions after removal of item from the hash table.
454 *
455 * @param item Item that was removed from the hash table.
456 *
457 */
458void ns_remove(link_t *item)
459{
460 assert(item);
461 free(hash_table_get_instance(item, hashed_service_t, link));
462}
463
464/**
465 * @}
466 */
Note: See TracBrowser for help on using the repository browser.