Changeset 40313e4 in mainline


Ignore:
Timestamp:
2009-06-03T18:45:33Z (15 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bf1fb9f
Parents:
5d0e461
Message:

split naming service into multiple files for better readability
add support for waiting on tasks (receives kernel task notifications)

Location:
uspace/srv/ns
Files:
7 added
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/ns/Makefile

    r5d0e461 r40313e4  
    4242OUTPUT = ns
    4343SOURCES = \
    44         ns.c
     44        ns.c \
     45        service.c \
     46        clonable.c \
     47        task.c
    4548
    4649OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
  • uspace/srv/ns/ns.c

    r5d0e461 r40313e4  
    3636 */
    3737
    38 
    3938#include <ipc/ipc.h>
     39#include <ipc/services.h>
    4040#include <ipc/ns.h>
    41 #include <ipc/services.h>
     41#include <unistd.h>
    4242#include <stdio.h>
    43 #include <bool.h>
    44 #include <unistd.h>
    45 #include <stdlib.h>
    4643#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>
     44#include <as.h>
    5245#include <ddi.h>
    53 #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,
    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 {
    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 {
    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;
    102 
    103 /** Request for connection to a clonable service. */
    104 typedef 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. */
    112 static link_t cs_req;
     46#include <event.h>
     47#include <macros.h>
     48#include "ns.h"
     49#include "service.h"
     50#include "clonable.h"
     51#include "task.h"
    11352
    11453static void *clockaddr = NULL;
    11554static void *klogaddr = NULL;
    11655
    117 /** Return true if @a service is clonable. */
    118 static bool service_clonable(int service)
    119 {
    120         return (service == SERVICE_LOAD);
    121 }
    122 
    123 static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr)
     56static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr,
     57    size_t pages, void **addr)
    12458{
    12559        if (ph_addr == NULL) {
     
    14680}
    14781
    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 
    18082int main(int argc, char **argv)
    18183{
    18284        printf(NAME ": HelenOS IPC Naming Service\n");
    18385       
    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         }
     86        int rc = service_init();
     87        if (rc != EOK)
     88                return rc;
    18989       
    190         list_initialize(&pending_req);
    191         list_initialize(&cs_req);
     90        rc = clonable_init();
     91        if (rc != EOK)
     92                return rc;
     93       
     94        rc = task_init();
     95        if (rc != EOK)
     96                return rc;
    19297       
    19398        printf(NAME ": Accepting connections\n");
     99       
    194100        while (true) {
    195                 process_pending_req();
     101                process_pending_conn();
     102                process_pending_wait();
    196103               
    197104                ipc_call_t call;
    198105                ipc_callid_t callid = ipc_wait_for_call(&call);
     106               
     107                task_id_t id;
    199108                ipcarg_t retval;
     109               
     110                if (callid & IPC_CALLID_NOTIFICATION) {
     111                        id = (task_id_t)
     112                            MERGE_LOUP32(IPC_GET_ARG2(call), IPC_GET_ARG3(call));
     113                        wait_notification((wait_type_t) IPC_GET_ARG1(call), id);
     114                        continue;
     115                }
    200116               
    201117                switch (IPC_GET_METHOD(call)) {
     
    203119                        switch (IPC_GET_ARG3(call)) {
    204120                        case SERVICE_MEM_REALTIME:
    205                                 get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr);
     121                                get_as_area(callid, &call,
     122                                    (void *) sysinfo_value("clock.faddr"),
     123                                    1, &clockaddr);
    206124                                break;
    207125                        case SERVICE_MEM_KLOG:
    208                                 get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr);
     126                                get_as_area(callid, &call,
     127                                    (void *) sysinfo_value("klog.faddr"),
     128                                    sysinfo_value("klog.pages"), &klogaddr);
    209129                                break;
    210130                        default:
     
    242162                        }
    243163                        break;
     164                case NS_PING:
     165                        retval = EOK;
     166                        break;
     167                case NS_TASK_WAIT:
     168                        id = (task_id_t)
     169                            MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     170                        wait_for_task(id, &call, callid);
     171                        continue;
    244172                default:
    245173                        retval = ENOENT;
     
    255183}
    256184
    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 
    464185/**
    465186 * @}
Note: See TracChangeset for help on using the changeset viewer.