Subversion Repositories HelenOS

Rev

Rev 4618 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2009 Martin Decky
  3.  * Copyright (c) 2009 Jiri Svoboda
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. /** @addtogroup ns
  31.  * @{
  32.  */
  33.  
  34. #include <ipc/ipc.h>
  35. #include <adt/hash_table.h>
  36. #include <bool.h>
  37. #include <errno.h>
  38. #include <assert.h>
  39. #include <stdio.h>
  40. #include <macros.h>
  41. #include "task.h"
  42. #include "ns.h"
  43.  
  44. #define TASK_HASH_TABLE_CHAINS  256
  45. #define P2I_HASH_TABLE_CHAINS  256
  46.  
  47. static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id);
  48.  
  49. /* TODO:
  50.  *
  51.  * As there is currently no convention that each task has to be waited
  52.  * for, the NS can leak memory because of the zombie tasks.
  53.  *
  54.  */
  55.  
  56. /** Task hash table item. */
  57. typedef struct {
  58.     link_t link;
  59.     task_id_t id;    /**< Task ID. */
  60.     int retval;
  61.     bool destroyed;
  62. } hashed_task_t;
  63.  
  64. /** Compute hash index into task hash table.
  65.  *
  66.  * @param key Pointer keys. However, only the first key (i.e. truncated task
  67.  *            number) is used to compute the hash index.
  68.  *
  69.  * @return Hash index corresponding to key[0].
  70.  *
  71.  */
  72. static hash_index_t task_hash(unsigned long *key)
  73. {
  74.     assert(key);
  75.     return (LOWER32(*key) % TASK_HASH_TABLE_CHAINS);
  76. }
  77.  
  78. /** Compare a key with hashed item.
  79.  *
  80.  * @param key  Array of keys.
  81.  * @param keys Must be less than or equal to 2.
  82.  * @param item Pointer to a hash table item.
  83.  *
  84.  * @return Non-zero if the key matches the item, zero otherwise.
  85.  *
  86.  */
  87. static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
  88. {
  89.     assert(key);
  90.     assert(keys <= 2);
  91.     assert(item);
  92.    
  93.     hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
  94.    
  95.     if (keys == 2)
  96.         return ((LOWER32(key[1]) == UPPER32(ht->id))
  97.             && (LOWER32(key[0]) == LOWER32(ht->id)));
  98.     else
  99.         return (LOWER32(key[0]) == LOWER32(ht->id));
  100. }
  101.  
  102. /** Perform actions after removal of item from the hash table.
  103.  *
  104.  * @param item Item that was removed from the hash table.
  105.  *
  106.  */
  107. static void task_remove(link_t *item)
  108. {
  109.     assert(item);
  110.     free(hash_table_get_instance(item, hashed_task_t, link));
  111. }
  112.  
  113. /** Operations for task hash table. */
  114. static hash_table_operations_t task_hash_table_ops = {
  115.     .hash = task_hash,
  116.     .compare = task_compare,
  117.     .remove_callback = task_remove
  118. };
  119.  
  120. /** Task hash table structure. */
  121. static hash_table_t task_hash_table;
  122.  
  123. typedef struct {
  124.     link_t link;
  125.     ipcarg_t phash;    /**< Task ID. */
  126.     task_id_t id;    /**< Task ID. */
  127. } p2i_entry_t;
  128.  
  129. /** Compute hash index into task hash table.
  130.  *
  131.  * @param key Array of keys.
  132.  * @return Hash index corresponding to key[0].
  133.  *
  134.  */
  135. static hash_index_t p2i_hash(unsigned long *key)
  136. {
  137.     assert(key);
  138.     return (*key % TASK_HASH_TABLE_CHAINS);
  139. }
  140.  
  141. /** Compare a key with hashed item.
  142.  *
  143.  * @param key  Array of keys.
  144.  * @param keys Must be less than or equal to 1.
  145.  * @param item Pointer to a hash table item.
  146.  *
  147.  * @return Non-zero if the key matches the item, zero otherwise.
  148.  *
  149.  */
  150. static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item)
  151. {
  152.     assert(key);
  153.     assert(keys == 1);
  154.     assert(item);
  155.  
  156.     p2i_entry_t *e = hash_table_get_instance(item, p2i_entry_t, link);
  157.  
  158.     return (key[0] == e->phash);
  159. }
  160.  
  161. /** Perform actions after removal of item from the hash table.
  162.  *
  163.  * @param item Item that was removed from the hash table.
  164.  *
  165.  */
  166. static void p2i_remove(link_t *item)
  167. {
  168.     assert(item);
  169.     free(hash_table_get_instance(item, p2i_entry_t, link));
  170. }
  171.  
  172. /** Operations for task hash table. */
  173. static hash_table_operations_t p2i_ops = {
  174.     .hash = p2i_hash,
  175.     .compare = p2i_compare,
  176.     .remove_callback = p2i_remove
  177. };
  178.  
  179. /** Map phone hash to task ID */
  180. static hash_table_t phone_to_id;
  181.  
  182. /** Pending task wait structure. */
  183. typedef struct {
  184.     link_t link;
  185.     task_id_t id;         /**< Task ID. */
  186.     ipc_callid_t callid;  /**< Call ID waiting for the connection */
  187. } pending_wait_t;
  188.  
  189. static link_t pending_wait;
  190.  
  191. int task_init(void)
  192. {
  193.     if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
  194.         2, &task_hash_table_ops)) {
  195.         printf(NAME ": No memory available for tasks\n");
  196.         return ENOMEM;
  197.     }
  198.  
  199.     if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS,
  200.         1, &p2i_ops)) {
  201.         printf(NAME ": No memory available for tasks\n");
  202.         return ENOMEM;
  203.     }
  204.    
  205.     list_initialize(&pending_wait);
  206.    
  207.     return EOK;
  208. }
  209.  
  210. /** Process pending wait requests */
  211. void process_pending_wait(void)
  212. {
  213.     link_t *cur;
  214.    
  215. loop:
  216.     for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
  217.         pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
  218.        
  219.         unsigned long keys[2] = {
  220.             LOWER32(pr->id),
  221.             UPPER32(pr->id)
  222.         };
  223.        
  224.         link_t *link = hash_table_find(&task_hash_table, keys);
  225.         if (!link)
  226.             continue;
  227.        
  228.         hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
  229.         if (!ht->destroyed)
  230.             continue;
  231.        
  232.         if (!(pr->callid & IPC_CALLID_NOTIFICATION))
  233.             ipc_answer_1(pr->callid, EOK, ht->retval);
  234.        
  235.         hash_table_remove(&task_hash_table, keys, 2);
  236.         list_remove(cur);
  237.         free(pr);
  238.         goto loop;
  239.     }
  240. }
  241.  
  242. void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid)
  243. {
  244.     ipcarg_t retval;
  245.     unsigned long keys[2] = {
  246.         LOWER32(id),
  247.         UPPER32(id)
  248.     };
  249.  
  250.     link_t *link = hash_table_find(&task_hash_table, keys);
  251.     hashed_task_t *ht = (link != NULL) ?
  252.         hash_table_get_instance(link, hashed_task_t, link) : NULL;
  253.  
  254.     if (ht == NULL) {
  255.         /* No such task exists. */
  256.         retval = ENOENT;
  257.         goto out;
  258.     }
  259.  
  260.     if (!ht->destroyed) {
  261.         /* Add to pending list */
  262.         pending_wait_t *pr =
  263.             (pending_wait_t *) malloc(sizeof(pending_wait_t));
  264.         if (!pr) {
  265.             retval = ENOMEM;
  266.             goto out;
  267.         }
  268.        
  269.         pr->id = id;
  270.         pr->callid = callid;
  271.         list_append(&pr->link, &pending_wait);
  272.         return;
  273.     }
  274.    
  275.     hash_table_remove(&task_hash_table, keys, 2);
  276.     retval = EOK;
  277.    
  278. out:
  279.     if (!(callid & IPC_CALLID_NOTIFICATION))
  280.         ipc_answer_1(callid, retval, ht->retval);
  281. }
  282.  
  283. int ns_task_id_intro(ipc_call_t *call)
  284. {
  285.     task_id_t id;
  286.     unsigned long keys[2];
  287.     link_t *link;
  288.     p2i_entry_t *e;
  289.     hashed_task_t *ht;
  290.  
  291.     id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
  292.  
  293.     keys[0] = call->in_phone_hash;
  294.  
  295.     link = hash_table_find(&phone_to_id, keys);
  296.     if (link != NULL)
  297.         return EEXISTS;
  298.  
  299.     e = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
  300.     if (e == NULL)
  301.         return ENOMEM;
  302.  
  303.     ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
  304.     if (ht == NULL)
  305.         return ENOMEM;
  306.  
  307.     /* Insert to phone-to-id map. */
  308.  
  309.     link_initialize(&e->link);
  310.     e->phash = call->in_phone_hash;
  311.     e->id = id;
  312.     hash_table_insert(&phone_to_id, keys, &e->link);
  313.  
  314.     /* Insert to main table. */
  315.  
  316.     keys[0] = LOWER32(id);
  317.     keys[1] = UPPER32(id);
  318.  
  319.     link_initialize(&ht->link);
  320.     ht->id = id;
  321.     ht->destroyed = false;
  322.     ht->retval = -1;
  323.     hash_table_insert(&task_hash_table, keys, &ht->link);
  324.  
  325.     return EOK;
  326. }
  327.  
  328. int ns_task_retval(ipc_call_t *call)
  329. {
  330.     task_id_t id;
  331.     unsigned long keys[2];
  332.     int rc;
  333.  
  334.     rc = get_id_by_phone(call->in_phone_hash, &id);
  335.     if (rc != EOK)
  336.         return rc;
  337.  
  338.     keys[0] = LOWER32(id);
  339.     keys[1] = UPPER32(id);
  340.    
  341.     link_t *link = hash_table_find(&task_hash_table, keys);
  342.     hashed_task_t *ht = (link != NULL) ?
  343.         hash_table_get_instance(link, hashed_task_t, link) : NULL;
  344.    
  345.     if ((ht == NULL) || ht->destroyed)
  346.         return EINVAL;
  347.  
  348.     ht->retval = IPC_GET_ARG1(*call);
  349.  
  350.     return EOK;
  351. }
  352.  
  353. int ns_task_disconnect(ipc_call_t *call)
  354. {
  355.     unsigned long keys[2];
  356.     task_id_t id;
  357.     int rc;
  358.  
  359.     rc = get_id_by_phone(call->in_phone_hash, &id);
  360.     if (rc != EOK)
  361.         return rc;
  362.  
  363.     /* Delete from phone-to-id map. */
  364.     keys[0] = call->in_phone_hash;
  365.     hash_table_remove(&phone_to_id, keys, 1);
  366.  
  367.     /* Mark task as finished. */
  368.     keys[0] = LOWER32(id);
  369.     keys[1] = UPPER32(id);
  370.  
  371.     link_t *link = hash_table_find(&task_hash_table, keys);
  372.     hashed_task_t *ht =
  373.         hash_table_get_instance(link, hashed_task_t, link);
  374.     assert(ht != NULL);
  375.  
  376.     ht->destroyed = true;
  377.  
  378.     return EOK;
  379. }
  380.  
  381. static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id)
  382. {
  383.     unsigned long keys[1];
  384.     link_t *link;
  385.     p2i_entry_t *e;
  386.  
  387.     keys[0] = phone_hash;
  388.     link = hash_table_find(&phone_to_id, keys);
  389.     if (link == NULL)
  390.         return ENOENT;
  391.  
  392.     e = hash_table_get_instance(link, p2i_entry_t, link);
  393.     *id = e->id;
  394.  
  395.     return EOK;
  396. }
  397.  
  398. /**
  399.  * @}
  400.  */
  401.