Subversion Repositories HelenOS

Rev

Rev 4348 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4348 Rev 4691
Line 33... Line 33...
33
/**
33
/**
34
 * @file  ns.c
34
 * @file  ns.c
35
 * @brief Naming service for HelenOS IPC.
35
 * @brief Naming service for HelenOS IPC.
36
 */
36
 */
37
 
37
 
38
 
-
 
39
#include <ipc/ipc.h>
38
#include <ipc/ipc.h>
40
#include <ipc/ns.h>
-
 
41
#include <ipc/services.h>
39
#include <ipc/services.h>
42
#include <stdio.h>
40
#include <ipc/ns.h>
43
#include <bool.h>
-
 
44
#include <unistd.h>
41
#include <unistd.h>
45
#include <stdlib.h>
42
#include <stdio.h>
46
#include <errno.h>
43
#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>
44
#include <as.h>
54
 
-
 
55
#define NAME  "ns"
-
 
56
 
-
 
57
#define NS_HASH_TABLE_CHAINS  20
-
 
58
 
-
 
59
static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
-
 
60
static void connect_to_service(ipcarg_t service, ipc_call_t *call,
-
 
61
    ipc_callid_t callid);
-
 
62
 
-
 
63
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
-
 
64
    ipc_callid_t callid);
-
 
65
void 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. */
-
 
70
static hash_index_t ns_hash(unsigned long *key);
-
 
71
static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item);
-
 
72
static void ns_remove(link_t *item);
-
 
73
 
-
 
74
/** Operations for NS hash table. */
-
 
75
static hash_table_operations_t ns_hash_table_ops = {
-
 
76
    .hash = ns_hash,
45
#include <ddi.h>
77
    .compare = ns_compare,
-
 
78
    .remove_callback = ns_remove
-
 
79
};
-
 
80
 
-
 
81
/** NS hash table structure. */
-
 
82
static hash_table_t ns_hash_table;
-
 
83
 
-
 
84
/** NS hash table item. */
-
 
85
typedef struct {
46
#include <event.h>
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. */
-
 
93
typedef struct {
47
#include <macros.h>
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
 
-
 
101
static link_t pending_req;
48
#include <sysinfo.h>
102
 
-
 
103
/** Request for connection to a clonable service. */
-
 
104
typedef struct {
-
 
105
    link_t link;
49
#include "ns.h"
106
    ipcarg_t service;
50
#include "service.h"
107
    ipc_call_t call;
51
#include "clonable.h"
108
    ipc_callid_t callid;
52
#include "task.h"
109
} cs_req_t;
-
 
110
 
-
 
111
/** List of clonable-service connection requests. */
-
 
112
static link_t cs_req;
-
 
113
 
53
 
114
static void *clockaddr = NULL;
54
static void *clockaddr = NULL;
115
static void *klogaddr = NULL;
55
static void *klogaddr = NULL;
116
 
56
 
117
/** Return true if @a service is clonable. */
-
 
118
static bool service_clonable(int service)
57
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr,
119
{
-
 
120
    return (service == SERVICE_LOAD);
58
    size_t pages, void **addr)
121
}
-
 
122
 
-
 
123
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr)
-
 
124
{
59
{
125
    if (ph_addr == NULL) {
60
    if (ph_addr == NULL) {
126
        ipc_answer_0(callid, ENOENT);
61
        ipc_answer_0(callid, ENOENT);
127
        return;
62
        return;
128
    }
63
    }
Line 143... Line 78...
143
    }
78
    }
144
   
79
   
145
    ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ);
80
    ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ);
146
}
81
}
147
 
82
 
148
/** Process pending connection requests */
-
 
149
static void process_pending_req()
-
 
150
{
-
 
151
    link_t *cur;
-
 
152
   
-
 
153
loop:
-
 
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
 
-
 
180
int main(int argc, char **argv)
83
int main(int argc, char **argv)
181
{
84
{
182
    printf(NAME ": HelenOS IPC Naming Service\n");
85
    printf(NAME ": HelenOS IPC Naming Service\n");
183
   
86
   
184
    if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3,
-
 
185
        &ns_hash_table_ops)) {
87
    int rc = service_init();
186
        printf(NAME ": No memory available for services\n");
88
    if (rc != EOK)
187
        return ENOMEM;
89
        return rc;
188
    }
90
   
-
 
91
    rc = clonable_init();
-
 
92
    if (rc != EOK)
-
 
93
        return rc;
189
   
94
   
190
    list_initialize(&pending_req);
95
    rc = task_init();
-
 
96
    if (rc != EOK)
191
    list_initialize(&cs_req);
97
        return rc;
192
   
98
   
193
    printf(NAME ": Accepting connections\n");
99
    printf(NAME ": Accepting connections\n");
-
 
100
   
194
    while (true) {
101
    while (true) {
-
 
102
        process_pending_conn();
195
        process_pending_req();
103
        process_pending_wait();
196
       
104
       
197
        ipc_call_t call;
105
        ipc_call_t call;
198
        ipc_callid_t callid = ipc_wait_for_call(&call);
106
        ipc_callid_t callid = ipc_wait_for_call(&call);
-
 
107
       
-
 
108
        task_id_t id;
199
        ipcarg_t retval;
109
        ipcarg_t retval;
200
       
110
       
201
        switch (IPC_GET_METHOD(call)) {
111
        switch (IPC_GET_METHOD(call)) {
202
        case IPC_M_SHARE_IN:
112
        case IPC_M_SHARE_IN:
203
            switch (IPC_GET_ARG3(call)) {
113
            switch (IPC_GET_ARG3(call)) {
204
            case SERVICE_MEM_REALTIME:
114
            case SERVICE_MEM_REALTIME:
-
 
115
                get_as_area(callid, &call,
205
                get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr);
116
                    (void *) sysinfo_value("clock.faddr"),
-
 
117
                    1, &clockaddr);
206
                break;
118
                break;
207
            case SERVICE_MEM_KLOG:
119
            case SERVICE_MEM_KLOG:
-
 
120
                get_as_area(callid, &call,
-
 
121
                    (void *) sysinfo_value("klog.faddr"),
208
                get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr);
122
                    sysinfo_value("klog.pages"), &klogaddr);
209
                break;
123
                break;
210
            default:
124
            default:
211
                ipc_answer_0(callid, ENOENT);
125
                ipc_answer_0(callid, ENOENT);
212
            }
126
            }
213
            continue;
127
            continue;
214
        case IPC_M_PHONE_HUNGUP:
128
        case IPC_M_PHONE_HUNGUP:
215
            retval = EOK;
129
            retval = ns_task_disconnect(&call);
216
            break;
130
            break;
217
        case IPC_M_CONNECT_TO_ME:
131
        case IPC_M_CONNECT_TO_ME:
218
            /*
132
            /*
219
             * Server requests service registration.
133
             * Server requests service registration.
220
             */
134
             */
Line 239... Line 153...
239
                connect_to_service(IPC_GET_ARG1(call), &call,
153
                connect_to_service(IPC_GET_ARG1(call), &call,
240
                    callid);
154
                    callid);
241
                continue;
155
                continue;
242
            }
156
            }
243
            break;
157
            break;
-
 
158
        case NS_PING:
-
 
159
            retval = EOK;
-
 
160
            break;
-
 
161
        case NS_TASK_WAIT:
-
 
162
            id = (task_id_t)
-
 
163
                MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-
 
164
            wait_for_task(id, &call, callid);
-
 
165
            continue;
-
 
166
        case NS_ID_INTRO:
-
 
167
            retval = ns_task_id_intro(&call);
-
 
168
            break;
-
 
169
        case NS_RETVAL:
-
 
170
            retval = ns_task_retval(&call);
-
 
171
            break;
244
        default:
172
        default:
245
            retval = ENOENT;
173
            retval = ENOENT;
246
            break;
174
            break;
247
        }
175
        }
248
       
176
       
Line 252... Line 180...
252
   
180
   
253
    /* Not reached */
181
    /* Not reached */
254
    return 0;
182
    return 0;
255
}
183
}
256
 
184
 
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
 */
-
 
266
int 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
 */
-
 
299
void 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);
-
 
332
out:
-
 
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
 */
-
 
344
void 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
 */
-
 
378
void 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
 */
-
 
418
hash_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
 */
-
 
439
int 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
 */
-
 
458
void ns_remove(link_t *item)
-
 
459
{
-
 
460
    assert(item);
-
 
461
    free(hash_table_get_instance(item, hashed_service_t, link));
-
 
462
}
-
 
463
 
-
 
464
/**
185
/**
465
 * @}
186
 * @}
466
 */
187
 */