Subversion Repositories HelenOS

Rev

Rev 4620 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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