~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/srv/ns/service.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2009 Martin Decky
 
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
#include <ipc/ipc.h>
 
34
#include <adt/hash_table.h>
 
35
#include <assert.h>
 
36
#include <errno.h>
 
37
#include "service.h"
 
38
#include "ns.h"
 
39
 
 
40
#define SERVICE_HASH_TABLE_CHAINS  20
 
41
 
 
42
/** Service hash table item. */
 
43
typedef struct {
 
44
        link_t link;
 
45
        ipcarg_t service;        /**< Number of the service. */
 
46
        ipcarg_t phone;          /**< Phone registered with the service. */
 
47
        ipcarg_t in_phone_hash;  /**< Incoming phone hash. */
 
48
} hashed_service_t;
 
49
 
 
50
/** Compute hash index into service hash table.
 
51
 *
 
52
 * @param key Pointer keys. However, only the first key (i.e. service number)
 
53
 *            is used to compute the hash index.
 
54
 *
 
55
 * @return Hash index corresponding to key[0].
 
56
 *
 
57
 */
 
58
static hash_index_t service_hash(unsigned long *key)
 
59
{
 
60
        assert(key);
 
61
        return (*key % SERVICE_HASH_TABLE_CHAINS);
 
62
}
 
63
 
 
64
/** Compare a key with hashed item.
 
65
 *
 
66
 * This compare function always ignores the third key.
 
67
 * It exists only to make it possible to remove records
 
68
 * originating from connection with key[1] in_phone_hash
 
69
 * value. Note that this is close to being classified
 
70
 * as a nasty hack.
 
71
 *
 
72
 * @param key  Array of keys.
 
73
 * @param keys Must be lesser or equal to 3.
 
74
 * @param item Pointer to a hash table item.
 
75
 *
 
76
 * @return Non-zero if the key matches the item, zero otherwise.
 
77
 *
 
78
 */
 
79
static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
 
80
{
 
81
        assert(key);
 
82
        assert(keys <= 3);
 
83
        assert(item);
 
84
        
 
85
        hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
 
86
        
 
87
        if (keys == 2)
 
88
                return (key[1] == hs->in_phone_hash);
 
89
        else
 
90
                return (key[0] == hs->service);
 
91
}
 
92
 
 
93
/** Perform actions after removal of item from the hash table.
 
94
 *
 
95
 * @param item Item that was removed from the hash table.
 
96
 *
 
97
 */
 
98
static void service_remove(link_t *item)
 
99
{
 
100
        assert(item);
 
101
        free(hash_table_get_instance(item, hashed_service_t, link));
 
102
}
 
103
 
 
104
/** Operations for service hash table. */
 
105
static hash_table_operations_t service_hash_table_ops = {
 
106
        .hash = service_hash,
 
107
        .compare = service_compare,
 
108
        .remove_callback = service_remove
 
109
};
 
110
 
 
111
/** Service hash table structure. */
 
112
static hash_table_t service_hash_table;
 
113
 
 
114
/** Pending connection structure. */
 
115
typedef struct {
 
116
        link_t link;
 
117
        ipcarg_t service;        /**< Number of the service. */
 
118
        ipc_callid_t callid;     /**< Call ID waiting for the connection */
 
119
        ipcarg_t arg2;           /**< Second argument */
 
120
        ipcarg_t arg3;           /**< Third argument */
 
121
} pending_conn_t;
 
122
 
 
123
static link_t pending_conn;
 
124
 
 
125
int service_init(void)
 
126
{
 
127
        if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS,
 
128
            3, &service_hash_table_ops)) {
 
129
                printf(NAME ": No memory available for services\n");
 
130
                return ENOMEM;
 
131
        }
 
132
        
 
133
        list_initialize(&pending_conn);
 
134
        
 
135
        return EOK;
 
136
}
 
137
 
 
138
/** Process pending connection requests */
 
139
void process_pending_conn(void)
 
140
{
 
141
        link_t *cur;
 
142
        
 
143
loop:
 
144
        for (cur = pending_conn.next; cur != &pending_conn; cur = cur->next) {
 
145
                pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link);
 
146
                
 
147
                unsigned long keys[3] = {
 
148
                        pr->service,
 
149
                        0,
 
150
                        0
 
151
                };
 
152
                
 
153
                link_t *link = hash_table_find(&service_hash_table, keys);
 
154
                if (!link)
 
155
                        continue;
 
156
                
 
157
                hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
 
158
                ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
 
159
                    pr->arg2, pr->arg3, 0, IPC_FF_NONE);
 
160
                
 
161
                if (!(pr->callid & IPC_CALLID_NOTIFICATION))
 
162
                        ipc_answer_0(pr->callid, retval);
 
163
                
 
164
                list_remove(cur);
 
165
                free(pr);
 
166
                goto loop;
 
167
        }
 
168
}
 
169
 
 
170
/** Register service.
 
171
 *
 
172
 * @param service Service to be registered.
 
173
 * @param phone   Phone to be used for connections to the service.
 
174
 * @param call    Pointer to call structure.
 
175
 *
 
176
 * @return Zero on success or a value from @ref errno.h.
 
177
 *
 
178
 */
 
179
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
 
180
{
 
181
        unsigned long keys[3] = {
 
182
                service,
 
183
                call->in_phone_hash,
 
184
                0
 
185
        };
 
186
        
 
187
        if (hash_table_find(&service_hash_table, keys))
 
188
                return EEXISTS;
 
189
        
 
190
        hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
 
191
        if (!hs)
 
192
                return ENOMEM;
 
193
        
 
194
        link_initialize(&hs->link);
 
195
        hs->service = service;
 
196
        hs->phone = phone;
 
197
        hs->in_phone_hash = call->in_phone_hash;
 
198
        hash_table_insert(&service_hash_table, keys, &hs->link);
 
199
        
 
200
        return 0;
 
201
}
 
202
 
 
203
/** Connect client to service.
 
204
 *
 
205
 * @param service Service to be connected to.
 
206
 * @param call    Pointer to call structure.
 
207
 * @param callid  Call ID of the request.
 
208
 *
 
209
 * @return Zero on success or a value from @ref errno.h.
 
210
 *
 
211
 */
 
212
void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
 
213
{
 
214
        ipcarg_t retval;
 
215
        unsigned long keys[3] = {
 
216
                service,
 
217
                0,
 
218
                0
 
219
        };
 
220
        
 
221
        link_t *link = hash_table_find(&service_hash_table, keys);
 
222
        if (!link) {
 
223
                if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
 
224
                        /* Blocking connection, add to pending list */
 
225
                        pending_conn_t *pr =
 
226
                            (pending_conn_t *) malloc(sizeof(pending_conn_t));
 
227
                        if (!pr) {
 
228
                                retval = ENOMEM;
 
229
                                goto out;
 
230
                        }
 
231
                        
 
232
                        pr->service = service;
 
233
                        pr->callid = callid;
 
234
                        pr->arg2 = IPC_GET_ARG2(*call);
 
235
                        pr->arg3 = IPC_GET_ARG3(*call);
 
236
                        list_append(&pr->link, &pending_conn);
 
237
                        return;
 
238
                }
 
239
                retval = ENOENT;
 
240
                goto out;
 
241
        }
 
242
        
 
243
        hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
 
244
        retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
 
245
            IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
 
246
        
 
247
out:
 
248
        if (!(callid & IPC_CALLID_NOTIFICATION))
 
249
                ipc_answer_0(callid, retval);
 
250
}
 
251
 
 
252
/**
 
253
 * @}
 
254
 */