source: mainline/uspace/lib/c/generic/loc.c@ a75f3e49

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a75f3e49 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 19.7 KB
RevLine 
[15f3c3f]1/*
2 * Copyright (c) 2007 Josef Cejka
[cc574511]3 * Copyright (c) 2011 Jiri Svoboda
[15f3c3f]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#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/loc.h>
34#include <loc.h>
35#include <fibril_synch.h>
36#include <async.h>
37#include <errno.h>
[38d150e]38#include <stdlib.h>
[3e6a98c5]39#include <stdbool.h>
[15f3c3f]40
41static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
43
44static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex);
45static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
46
[12f9f0d0]47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
[a6240a31]49static loc_cat_change_cb_t cat_change_cb = NULL;
[12f9f0d0]50
[15f3c3f]51static async_sess_t *loc_supp_block_sess = NULL;
52static async_sess_t *loc_cons_block_sess = NULL;
53
54static async_sess_t *loc_supplier_sess = NULL;
55static async_sess_t *loc_consumer_sess = NULL;
56
[984a9ba]57static void loc_cb_conn(ipc_call_t *icall, void *arg)
[12f9f0d0]58{
59 while (true) {
60 ipc_call_t call;
[984a9ba]61 async_get_call(&call);
[a35b458]62
[12f9f0d0]63 if (!IPC_GET_IMETHOD(call)) {
64 /* TODO: Handle hangup */
65 return;
66 }
[a35b458]67
[12f9f0d0]68 switch (IPC_GET_IMETHOD(call)) {
69 case LOC_EVENT_CAT_CHANGE:
70 fibril_mutex_lock(&loc_callback_mutex);
[a6240a31]71 loc_cat_change_cb_t cb_fun = cat_change_cb;
[12f9f0d0]72 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]73
[984a9ba]74 async_answer_0(&call, EOK);
[a35b458]75
[a6240a31]76 if (cb_fun != NULL)
77 (*cb_fun)();
[a35b458]78
[12f9f0d0]79 break;
80 default:
[984a9ba]81 async_answer_0(&call, ENOTSUP);
[12f9f0d0]82 }
83 }
84}
85
86
[15f3c3f]87static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
88 async_sess_t **dst)
89{
90 fibril_mutex_lock(mtx);
[a35b458]91
[15f3c3f]92 if ((*dst == NULL) && (src != NULL))
93 *dst = src;
[a35b458]94
[15f3c3f]95 fibril_mutex_unlock(mtx);
96}
97
[a6240a31]98/** Create callback
99 *
100 * Must be called with loc_callback_mutex locked.
101 *
102 * @return EOK on success.
103 *
104 */
[b7fd2a0]105static errno_t loc_callback_create(void)
[12f9f0d0]106{
107 if (!loc_callback_created) {
[a6240a31]108 async_exch_t *exch =
[f9b2cb4c]109 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]110
[12f9f0d0]111 ipc_call_t answer;
112 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
[a35b458]113
[f9b2cb4c]114 port_id_t port;
[b7fd2a0]115 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
[f9b2cb4c]116 loc_cb_conn, NULL, &port);
[a35b458]117
[12f9f0d0]118 loc_exchange_end(exch);
[a35b458]119
[12f9f0d0]120 if (rc != EOK)
[a6240a31]121 return rc;
[a35b458]122
[b7fd2a0]123 errno_t retval;
[cd66f3c]124 async_wait_for(req, &retval);
125 if (retval != EOK)
126 return retval;
[a35b458]127
[12f9f0d0]128 loc_callback_created = true;
129 }
[a35b458]130
[a6240a31]131 return EOK;
[12f9f0d0]132}
133
[15f3c3f]134/** Start an async exchange on the loc session (blocking).
135 *
136 * @param iface Location service interface to choose
137 *
138 * @return New exchange.
139 *
140 */
[f9b2cb4c]141async_exch_t *loc_exchange_begin_blocking(iface_t iface)
[15f3c3f]142{
143 switch (iface) {
[f9b2cb4c]144 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]145 fibril_mutex_lock(&loc_supp_block_mutex);
[a35b458]146
[15f3c3f]147 while (loc_supp_block_sess == NULL) {
148 clone_session(&loc_supplier_mutex, loc_supplier_sess,
149 &loc_supp_block_sess);
[a35b458]150
[15f3c3f]151 if (loc_supp_block_sess == NULL)
152 loc_supp_block_sess =
[f9b2cb4c]153 service_connect_blocking(SERVICE_LOC,
154 INTERFACE_LOC_SUPPLIER, 0);
[15f3c3f]155 }
[a35b458]156
[15f3c3f]157 fibril_mutex_unlock(&loc_supp_block_mutex);
[a35b458]158
[15f3c3f]159 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
160 &loc_supplier_sess);
[a35b458]161
[15f3c3f]162 return async_exchange_begin(loc_supp_block_sess);
[f9b2cb4c]163 case INTERFACE_LOC_CONSUMER:
[15f3c3f]164 fibril_mutex_lock(&loc_cons_block_mutex);
[a35b458]165
[15f3c3f]166 while (loc_cons_block_sess == NULL) {
167 clone_session(&loc_consumer_mutex, loc_consumer_sess,
168 &loc_cons_block_sess);
[a35b458]169
[15f3c3f]170 if (loc_cons_block_sess == NULL)
171 loc_cons_block_sess =
[f9b2cb4c]172 service_connect_blocking(SERVICE_LOC,
173 INTERFACE_LOC_CONSUMER, 0);
[15f3c3f]174 }
[a35b458]175
[15f3c3f]176 fibril_mutex_unlock(&loc_cons_block_mutex);
[a35b458]177
[15f3c3f]178 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
179 &loc_consumer_sess);
[a35b458]180
[15f3c3f]181 return async_exchange_begin(loc_cons_block_sess);
182 default:
183 return NULL;
184 }
185}
186
187/** Start an async exchange on the loc session.
188 *
189 * @param iface Location service interface to choose
190 *
191 * @return New exchange.
192 *
193 */
[f9b2cb4c]194async_exch_t *loc_exchange_begin(iface_t iface)
[15f3c3f]195{
196 switch (iface) {
[f9b2cb4c]197 case INTERFACE_LOC_SUPPLIER:
[15f3c3f]198 fibril_mutex_lock(&loc_supplier_mutex);
[a35b458]199
[15f3c3f]200 if (loc_supplier_sess == NULL)
201 loc_supplier_sess =
[f9b2cb4c]202 service_connect(SERVICE_LOC,
203 INTERFACE_LOC_SUPPLIER, 0);
[a35b458]204
[15f3c3f]205 fibril_mutex_unlock(&loc_supplier_mutex);
[a35b458]206
[15f3c3f]207 if (loc_supplier_sess == NULL)
208 return NULL;
[a35b458]209
[15f3c3f]210 return async_exchange_begin(loc_supplier_sess);
[f9b2cb4c]211 case INTERFACE_LOC_CONSUMER:
[15f3c3f]212 fibril_mutex_lock(&loc_consumer_mutex);
[a35b458]213
[15f3c3f]214 if (loc_consumer_sess == NULL)
215 loc_consumer_sess =
[f9b2cb4c]216 service_connect(SERVICE_LOC,
217 INTERFACE_LOC_CONSUMER, 0);
[a35b458]218
[15f3c3f]219 fibril_mutex_unlock(&loc_consumer_mutex);
[a35b458]220
[15f3c3f]221 if (loc_consumer_sess == NULL)
222 return NULL;
[a35b458]223
[15f3c3f]224 return async_exchange_begin(loc_consumer_sess);
225 default:
226 return NULL;
227 }
228}
229
230/** Finish an async exchange on the loc session.
231 *
232 * @param exch Exchange to be finished.
233 *
234 */
235void loc_exchange_end(async_exch_t *exch)
236{
237 async_exchange_end(exch);
238}
239
240/** Register new driver with loc. */
[b7fd2a0]241errno_t loc_server_register(const char *name)
[15f3c3f]242{
[f9b2cb4c]243 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[a35b458]244
[15f3c3f]245 ipc_call_t answer;
246 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
[b7fd2a0]247 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]248
[15f3c3f]249 if (retval != EOK) {
[50b581d]250 async_forget(req);
[0239846]251 loc_exchange_end(exch);
[15f3c3f]252 return retval;
253 }
[a35b458]254
[f9b2cb4c]255 async_connect_to_me(exch, 0, 0, 0);
[0239846]256
257 /*
258 * First wait for the answer and then end the exchange. The opposite
259 * order is generally wrong because it may lead to a deadlock under
260 * certain circumstances.
261 */
262 async_wait_for(req, &retval);
[15f3c3f]263 loc_exchange_end(exch);
[a35b458]264
[15f3c3f]265 return retval;
266}
267
[d0dd7b5]268/** Register new service.
[15f3c3f]269 *
[f9b2cb4c]270 * @param fqsn Fully qualified service name
271 * @param[out] sid Service ID of new service
[15f3c3f]272 *
273 */
[b7fd2a0]274errno_t loc_service_register(const char *fqsn, service_id_t *sid)
[15f3c3f]275{
[f9b2cb4c]276 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[a35b458]277
[15f3c3f]278 ipc_call_t answer;
[f9b2cb4c]279 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
[b7fd2a0]280 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
[a35b458]281
[15f3c3f]282 if (retval != EOK) {
[50b581d]283 async_forget(req);
[0239846]284 loc_exchange_end(exch);
[15f3c3f]285 return retval;
286 }
[a35b458]287
[0239846]288 /*
289 * First wait for the answer and then end the exchange. The opposite
290 * order is generally wrong because it may lead to a deadlock under
291 * certain circumstances.
292 */
[15f3c3f]293 async_wait_for(req, &retval);
[0239846]294 loc_exchange_end(exch);
[a35b458]295
[15f3c3f]296 if (retval != EOK) {
[d0dd7b5]297 if (sid != NULL)
298 *sid = -1;
[a35b458]299
[15f3c3f]300 return retval;
301 }
[a35b458]302
[d0dd7b5]303 if (sid != NULL)
304 *sid = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]305
[15f3c3f]306 return retval;
307}
308
[d0dd7b5]309/** Unregister service.
310 *
311 * @param sid Service ID
312 */
[b7fd2a0]313errno_t loc_service_unregister(service_id_t sid)
[d0dd7b5]314{
315 async_exch_t *exch;
[b7fd2a0]316 errno_t retval;
[a35b458]317
[f9b2cb4c]318 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[d0dd7b5]319 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
320 loc_exchange_end(exch);
[a35b458]321
[b7fd2a0]322 return (errno_t)retval;
[15f3c3f]323}
324
[b7fd2a0]325errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
[15f3c3f]326 unsigned int flags)
327{
328 async_exch_t *exch;
[a35b458]329
[15f3c3f]330 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]331 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]332 else {
[f9b2cb4c]333 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]334 if (exch == NULL)
335 return errno;
336 }
[a35b458]337
[15f3c3f]338 ipc_call_t answer;
339 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
340 &answer);
[b7fd2a0]341 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
[a35b458]342
[15f3c3f]343 loc_exchange_end(exch);
[a35b458]344
[15f3c3f]345 if (retval != EOK) {
[50b581d]346 async_forget(req);
[15f3c3f]347 return retval;
348 }
[a35b458]349
[15f3c3f]350 async_wait_for(req, &retval);
[a35b458]351
[15f3c3f]352 if (retval != EOK) {
353 if (handle != NULL)
354 *handle = (service_id_t) -1;
[a35b458]355
[15f3c3f]356 return retval;
357 }
[a35b458]358
[15f3c3f]359 if (handle != NULL)
360 *handle = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]361
[15f3c3f]362 return retval;
363}
364
[763e0cd]365/** Get object name.
[cce8a83]366 *
[763e0cd]367 * Provided ID of an object, return its name.
[cce8a83]368 *
[763e0cd]369 * @param method IPC method
370 * @param id Object ID
[cce8a83]371 * @param name Place to store pointer to new string. Caller should
372 * free it using free().
[cde999a]373 * @return EOK on success or an error code
[cce8a83]374 */
[b7fd2a0]375static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
[cce8a83]376{
377 async_exch_t *exch;
378 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]379 ipc_call_t dreply;
380 size_t act_size;
[b7fd2a0]381 errno_t dretval;
[a35b458]382
[cce8a83]383 *name = NULL;
[f9b2cb4c]384 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]385
[cce8a83]386 ipc_call_t answer;
[763e0cd]387 aid_t req = async_send_1(exch, method, id, &answer);
[45058baa]388 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
389 &dreply);
390 async_wait_for(dreq, &dretval);
[a35b458]391
[cce8a83]392 loc_exchange_end(exch);
[a35b458]393
[45058baa]394 if (dretval != EOK) {
[50b581d]395 async_forget(req);
[45058baa]396 return dretval;
[cce8a83]397 }
[a35b458]398
[b7fd2a0]399 errno_t retval;
[cce8a83]400 async_wait_for(req, &retval);
[a35b458]401
[cce8a83]402 if (retval != EOK)
403 return retval;
[a35b458]404
[45058baa]405 act_size = IPC_GET_ARG2(dreply);
406 assert(act_size <= LOC_NAME_MAXLEN);
407 name_buf[act_size] = '\0';
408
[cce8a83]409 *name = str_dup(name_buf);
410 if (*name == NULL)
411 return ENOMEM;
[a35b458]412
[cce8a83]413 return EOK;
414}
415
[763e0cd]416/** Get category name.
417 *
418 * Provided ID of a service, return its name.
419 *
420 * @param cat_id Category ID
421 * @param name Place to store pointer to new string. Caller should
422 * free it using free().
[cde999a]423 * @return EOK on success or an error code
[763e0cd]424 */
[b7fd2a0]425errno_t loc_category_get_name(category_id_t cat_id, char **name)
[763e0cd]426{
427 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
428}
429
430/** Get service name.
431 *
432 * Provided ID of a service, return its name.
433 *
434 * @param svc_id Service ID
435 * @param name Place to store pointer to new string. Caller should
436 * free it using free().
[cde999a]437 * @return EOK on success or an error code
[763e0cd]438 */
[b7fd2a0]439errno_t loc_service_get_name(service_id_t svc_id, char **name)
[763e0cd]440{
441 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
442}
[cce8a83]443
[a3fcfba]444/** Get service server name.
445 *
446 * Provided ID of a service, return the name of its server.
447 *
448 * @param svc_id Service ID
449 * @param name Place to store pointer to new string. Caller should
450 * free it using free().
[cde999a]451 * @return EOK on success or an error code
[a3fcfba]452 */
[b7fd2a0]453errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
[a3fcfba]454{
455 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
456}
457
[b7fd2a0]458errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
[15f3c3f]459 unsigned int flags)
460{
461 async_exch_t *exch;
[a35b458]462
[15f3c3f]463 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]464 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]465 else {
[f9b2cb4c]466 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[15f3c3f]467 if (exch == NULL)
468 return errno;
469 }
[a35b458]470
[15f3c3f]471 ipc_call_t answer;
472 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
473 &answer);
[b7fd2a0]474 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]475
[15f3c3f]476 loc_exchange_end(exch);
[a35b458]477
[15f3c3f]478 if (retval != EOK) {
[50b581d]479 async_forget(req);
[15f3c3f]480 return retval;
481 }
[a35b458]482
[15f3c3f]483 async_wait_for(req, &retval);
[a35b458]484
[15f3c3f]485 if (retval != EOK) {
486 if (handle != NULL)
487 *handle = (service_id_t) -1;
[a35b458]488
[15f3c3f]489 return retval;
490 }
[a35b458]491
[15f3c3f]492 if (handle != NULL)
493 *handle = (service_id_t) IPC_GET_ARG1(answer);
[a35b458]494
[15f3c3f]495 return retval;
496}
497
[cc574511]498/** Get category ID.
499 *
500 * Provided name of a category, return its ID.
501 *
502 * @param name Category name
503 * @param cat_id Place to store ID
504 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
[cde999a]505 * @return EOK on success or an error code
[cc574511]506 */
[b7fd2a0]507errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
[cc574511]508 unsigned int flags)
509{
510 async_exch_t *exch;
[a35b458]511
[cc574511]512 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]513 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]514 else {
[f9b2cb4c]515 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[cc574511]516 if (exch == NULL)
517 return errno;
518 }
[a35b458]519
[cc574511]520 ipc_call_t answer;
521 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
522 &answer);
[b7fd2a0]523 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]524
[cc574511]525 loc_exchange_end(exch);
[a35b458]526
[cc574511]527 if (retval != EOK) {
[50b581d]528 async_forget(req);
[cc574511]529 return retval;
530 }
[a35b458]531
[cc574511]532 async_wait_for(req, &retval);
[a35b458]533
[cc574511]534 if (retval != EOK) {
535 if (cat_id != NULL)
536 *cat_id = (category_id_t) -1;
[a35b458]537
[cc574511]538 return retval;
539 }
[a35b458]540
[cc574511]541 if (cat_id != NULL)
542 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
[a35b458]543
[cc574511]544 return retval;
545}
546
547
[15f3c3f]548loc_object_type_t loc_id_probe(service_id_t handle)
549{
[f9b2cb4c]550 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]551
[15f3c3f]552 sysarg_t type;
[b7fd2a0]553 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
[a35b458]554
[15f3c3f]555 loc_exchange_end(exch);
[a35b458]556
[15f3c3f]557 if (retval != EOK)
558 return LOC_OBJECT_NONE;
[a35b458]559
[15f3c3f]560 return (loc_object_type_t) type;
561}
562
[f9b2cb4c]563async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
[15f3c3f]564 unsigned int flags)
565{
566 async_sess_t *sess;
[a35b458]567
[15f3c3f]568 if (flags & IPC_FLAG_BLOCKING)
[f9b2cb4c]569 sess = service_connect_blocking(SERVICE_LOC, iface, handle);
[15f3c3f]570 else
[f9b2cb4c]571 sess = service_connect(SERVICE_LOC, iface, handle);
[a35b458]572
[15f3c3f]573 return sess;
574}
575
[d5c1051]576/**
577 * @return ID of a new NULL device, or -1 if failed.
578 */
[15f3c3f]579int loc_null_create(void)
580{
[f9b2cb4c]581 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[a35b458]582
[15f3c3f]583 sysarg_t null_id;
[b7fd2a0]584 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
[a35b458]585
[15f3c3f]586 loc_exchange_end(exch);
[a35b458]587
[15f3c3f]588 if (retval != EOK)
589 return -1;
[a35b458]590
[15f3c3f]591 return (int) null_id;
592}
593
594void loc_null_destroy(int null_id)
595{
[f9b2cb4c]596 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]597 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
598 loc_exchange_end(exch);
599}
600
601static size_t loc_count_namespaces_internal(async_exch_t *exch)
602{
603 sysarg_t count;
[b7fd2a0]604 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
[15f3c3f]605 if (retval != EOK)
606 return 0;
[a35b458]607
[15f3c3f]608 return count;
609}
610
[cc574511]611/** Add service to category.
612 *
613 * @param svc_id Service ID
614 * @param cat_id Category ID
[cde999a]615 * @return EOK on success or an error code
[cc574511]616 */
[b7fd2a0]617errno_t loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
[cc574511]618{
619 async_exch_t *exch;
[b7fd2a0]620 errno_t retval;
[a35b458]621
[f9b2cb4c]622 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
[cc574511]623 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
624 loc_exchange_end(exch);
[a35b458]625
[cc574511]626 return retval;
627}
628
[15f3c3f]629static size_t loc_count_services_internal(async_exch_t *exch,
630 service_id_t ns_handle)
631{
632 sysarg_t count;
[b7fd2a0]633 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
[15f3c3f]634 &count);
635 if (retval != EOK)
636 return 0;
[a35b458]637
[15f3c3f]638 return count;
639}
640
641size_t loc_count_namespaces(void)
642{
[f9b2cb4c]643 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]644 size_t size = loc_count_namespaces_internal(exch);
645 loc_exchange_end(exch);
[a35b458]646
[15f3c3f]647 return size;
648}
649
650size_t loc_count_services(service_id_t ns_handle)
651{
[f9b2cb4c]652 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]653 size_t size = loc_count_services_internal(exch, ns_handle);
654 loc_exchange_end(exch);
[a35b458]655
[15f3c3f]656 return size;
657}
658
659size_t loc_get_namespaces(loc_sdesc_t **data)
660{
[cc574511]661 /* Loop until read is succesful */
[15f3c3f]662 while (true) {
[f9b2cb4c]663 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]664 size_t count = loc_count_namespaces_internal(exch);
665 loc_exchange_end(exch);
[a35b458]666
[15f3c3f]667 if (count == 0)
668 return 0;
[a35b458]669
[15f3c3f]670 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
671 if (devs == NULL)
672 return 0;
[a35b458]673
[f9b2cb4c]674 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[a35b458]675
[15f3c3f]676 ipc_call_t answer;
677 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
[b7fd2a0]678 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]679
[15f3c3f]680 loc_exchange_end(exch);
[a35b458]681
[15f3c3f]682 if (rc == EOVERFLOW) {
683 /*
684 * Number of namespaces has changed since
685 * the last call of LOC_GET_NAMESPACE_COUNT
686 */
687 free(devs);
688 continue;
689 }
[a35b458]690
[15f3c3f]691 if (rc != EOK) {
[50b581d]692 async_forget(req);
[15f3c3f]693 free(devs);
694 return 0;
695 }
[a35b458]696
[b7fd2a0]697 errno_t retval;
[15f3c3f]698 async_wait_for(req, &retval);
[a35b458]699
[15f3c3f]700 if (retval != EOK)
701 return 0;
[a35b458]702
[15f3c3f]703 *data = devs;
704 return count;
705 }
706}
707
708size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
709{
[cc574511]710 /* Loop until read is succesful */
[15f3c3f]711 while (true) {
[f9b2cb4c]712 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[15f3c3f]713 size_t count = loc_count_services_internal(exch, ns_handle);
714 loc_exchange_end(exch);
[a35b458]715
[15f3c3f]716 if (count == 0)
717 return 0;
[a35b458]718
[15f3c3f]719 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
720 if (devs == NULL)
721 return 0;
[a35b458]722
[f9b2cb4c]723 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
[a35b458]724
[15f3c3f]725 ipc_call_t answer;
726 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
[b7fd2a0]727 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]728
[15f3c3f]729 loc_exchange_end(exch);
[a35b458]730
[15f3c3f]731 if (rc == EOVERFLOW) {
732 /*
733 * Number of services has changed since
734 * the last call of LOC_GET_SERVICE_COUNT
735 */
736 free(devs);
737 continue;
738 }
[a35b458]739
[15f3c3f]740 if (rc != EOK) {
[50b581d]741 async_forget(req);
[15f3c3f]742 free(devs);
743 return 0;
744 }
[a35b458]745
[b7fd2a0]746 errno_t retval;
[15f3c3f]747 async_wait_for(req, &retval);
[a35b458]748
[15f3c3f]749 if (retval != EOK)
750 return 0;
[a35b458]751
[15f3c3f]752 *data = devs;
753 return count;
754 }
755}
[cc574511]756
[b7fd2a0]757static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
[278ac72]758 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]759{
[f9b2cb4c]760 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
[cc574511]761
762 ipc_call_t answer;
[278ac72]763 aid_t req = async_send_1(exch, method, arg1, &answer);
[b7fd2a0]764 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
[a35b458]765
[cc574511]766 loc_exchange_end(exch);
[a35b458]767
[cc574511]768 if (rc != EOK) {
[50b581d]769 async_forget(req);
[cc574511]770 return rc;
771 }
[a35b458]772
[b7fd2a0]773 errno_t retval;
[cc574511]774 async_wait_for(req, &retval);
[a35b458]775
[cc574511]776 if (retval != EOK) {
777 return retval;
778 }
[a35b458]779
[cc574511]780 *act_size = IPC_GET_ARG1(answer);
781 return EOK;
782}
783
[278ac72]784/** Get list of IDs.
[cc574511]785 *
786 * Returns an allocated array of service IDs.
787 *
[278ac72]788 * @param method IPC method
789 * @param arg1 IPC argument 1
[cc574511]790 * @param data Place to store pointer to array of IDs
791 * @param count Place to store number of IDs
[cde999a]792 * @return EOK on success or an error code
[cc574511]793 */
[b7fd2a0]794static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
[278ac72]795 sysarg_t **data, size_t *count)
[cc574511]796{
797 *data = NULL;
[88057e3]798 *count = 0;
[a35b458]799
[88057e3]800 size_t act_size = 0;
[b7fd2a0]801 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
[278ac72]802 &act_size);
[cc574511]803 if (rc != EOK)
804 return rc;
[a35b458]805
[88057e3]806 size_t alloc_size = act_size;
807 service_id_t *ids = malloc(alloc_size);
[cc574511]808 if (ids == NULL)
809 return ENOMEM;
[a35b458]810
[cc574511]811 while (true) {
[278ac72]812 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]813 &act_size);
814 if (rc != EOK)
815 return rc;
[a35b458]816
[c1f27f1d]817 if (act_size <= alloc_size)
[cc574511]818 break;
[a35b458]819
[88057e3]820 alloc_size = act_size;
821 ids = realloc(ids, alloc_size);
[cc574511]822 if (ids == NULL)
823 return ENOMEM;
824 }
[a35b458]825
[cc574511]826 *count = act_size / sizeof(category_id_t);
827 *data = ids;
828 return EOK;
829}
[278ac72]830
831/** Get list of services in category.
832 *
833 * Returns an allocated array of service IDs.
834 *
835 * @param cat_id Category ID
836 * @param data Place to store pointer to array of IDs
837 * @param count Place to store number of IDs
[cde999a]838 * @return EOK on success or an error code
[278ac72]839 */
[b7fd2a0]840errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
[278ac72]841 size_t *count)
842{
843 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
844 data, count);
845}
846
847/** Get list of categories.
848 *
849 * Returns an allocated array of category IDs.
850 *
851 * @param data Place to store pointer to array of IDs
852 * @param count Place to store number of IDs
[cde999a]853 * @return EOK on success or an error code
[278ac72]854 */
[b7fd2a0]855errno_t loc_get_categories(category_id_t **data, size_t *count)
[278ac72]856{
857 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
858 data, count);
859}
[12f9f0d0]860
[b7fd2a0]861errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
[12f9f0d0]862{
[a6240a31]863 fibril_mutex_lock(&loc_callback_mutex);
864 if (loc_callback_create() != EOK) {
865 fibril_mutex_unlock(&loc_callback_mutex);
[12f9f0d0]866 return EIO;
[a6240a31]867 }
[a35b458]868
[12f9f0d0]869 cat_change_cb = cb_fun;
[a6240a31]870 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]871
[12f9f0d0]872 return EOK;
873}
Note: See TracBrowser for help on using the repository browser.