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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c53a705 was 45058baa, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Use async_data_read() instead of async_data_read_start() to get actual number of bytes read.

  • Property mode set to 100644
File size: 17.2 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 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#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>
38#include <malloc.h>
39#include <bool.h>
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
47static async_sess_t *loc_supp_block_sess = NULL;
48static async_sess_t *loc_cons_block_sess = NULL;
49
50static async_sess_t *loc_supplier_sess = NULL;
51static async_sess_t *loc_consumer_sess = NULL;
52
53static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
54 async_sess_t **dst)
55{
56 fibril_mutex_lock(mtx);
57
58 if ((*dst == NULL) && (src != NULL))
59 *dst = src;
60
61 fibril_mutex_unlock(mtx);
62}
63
64/** Start an async exchange on the loc session (blocking).
65 *
66 * @param iface Location service interface to choose
67 *
68 * @return New exchange.
69 *
70 */
71async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
72{
73 switch (iface) {
74 case LOC_PORT_SUPPLIER:
75 fibril_mutex_lock(&loc_supp_block_mutex);
76
77 while (loc_supp_block_sess == NULL) {
78 clone_session(&loc_supplier_mutex, loc_supplier_sess,
79 &loc_supp_block_sess);
80
81 if (loc_supp_block_sess == NULL)
82 loc_supp_block_sess =
83 service_connect_blocking(EXCHANGE_SERIALIZE,
84 SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
85 }
86
87 fibril_mutex_unlock(&loc_supp_block_mutex);
88
89 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
90 &loc_supplier_sess);
91
92 return async_exchange_begin(loc_supp_block_sess);
93 case LOC_PORT_CONSUMER:
94 fibril_mutex_lock(&loc_cons_block_mutex);
95
96 while (loc_cons_block_sess == NULL) {
97 clone_session(&loc_consumer_mutex, loc_consumer_sess,
98 &loc_cons_block_sess);
99
100 if (loc_cons_block_sess == NULL)
101 loc_cons_block_sess =
102 service_connect_blocking(EXCHANGE_SERIALIZE,
103 SERVICE_LOC, LOC_PORT_CONSUMER, 0);
104 }
105
106 fibril_mutex_unlock(&loc_cons_block_mutex);
107
108 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
109 &loc_consumer_sess);
110
111 return async_exchange_begin(loc_cons_block_sess);
112 default:
113 return NULL;
114 }
115}
116
117/** Start an async exchange on the loc session.
118 *
119 * @param iface Location service interface to choose
120 *
121 * @return New exchange.
122 *
123 */
124async_exch_t *loc_exchange_begin(loc_interface_t iface)
125{
126 switch (iface) {
127 case LOC_PORT_SUPPLIER:
128 fibril_mutex_lock(&loc_supplier_mutex);
129
130 if (loc_supplier_sess == NULL)
131 loc_supplier_sess =
132 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
133 LOC_PORT_SUPPLIER, 0);
134
135 fibril_mutex_unlock(&loc_supplier_mutex);
136
137 if (loc_supplier_sess == NULL)
138 return NULL;
139
140 return async_exchange_begin(loc_supplier_sess);
141 case LOC_PORT_CONSUMER:
142 fibril_mutex_lock(&loc_consumer_mutex);
143
144 if (loc_consumer_sess == NULL)
145 loc_consumer_sess =
146 service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
147 LOC_PORT_CONSUMER, 0);
148
149 fibril_mutex_unlock(&loc_consumer_mutex);
150
151 if (loc_consumer_sess == NULL)
152 return NULL;
153
154 return async_exchange_begin(loc_consumer_sess);
155 default:
156 return NULL;
157 }
158}
159
160/** Finish an async exchange on the loc session.
161 *
162 * @param exch Exchange to be finished.
163 *
164 */
165void loc_exchange_end(async_exch_t *exch)
166{
167 async_exchange_end(exch);
168}
169
170/** Register new driver with loc. */
171int loc_server_register(const char *name, async_client_conn_t conn)
172{
173 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
174
175 ipc_call_t answer;
176 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
177 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
178
179 loc_exchange_end(exch);
180
181 if (retval != EOK) {
182 async_wait_for(req, NULL);
183 return retval;
184 }
185
186 async_set_client_connection(conn);
187
188 exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
189 async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
190 loc_exchange_end(exch);
191
192 async_wait_for(req, &retval);
193 return retval;
194}
195
196/** Register new device.
197 *
198 * The @p interface is used when forwarding connection to the driver.
199 * If not 0, the first argument is the interface and the second argument
200 * is the service ID.
201 *
202 * When the interface is zero (default), the first argument is directly
203 * the handle (to ensure backward compatibility).
204 *
205 * @param fqdn Fully qualified device name.
206 * @param[out] handle Handle to the created instance of device.
207 * @param interface Interface when forwarding.
208 *
209 */
210int loc_service_register_with_iface(const char *fqdn,
211 service_id_t *handle, sysarg_t interface)
212{
213 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
214
215 ipc_call_t answer;
216 aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
217 &answer);
218 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
219
220 loc_exchange_end(exch);
221
222 if (retval != EOK) {
223 async_wait_for(req, NULL);
224 return retval;
225 }
226
227 async_wait_for(req, &retval);
228
229 if (retval != EOK) {
230 if (handle != NULL)
231 *handle = -1;
232
233 return retval;
234 }
235
236 if (handle != NULL)
237 *handle = (service_id_t) IPC_GET_ARG1(answer);
238
239 return retval;
240}
241
242/** Register new device.
243 *
244 * @param fqdn Fully qualified device name.
245 * @param handle Output: Handle to the created instance of device.
246 *
247 */
248int loc_service_register(const char *fqdn, service_id_t *handle)
249{
250 return loc_service_register_with_iface(fqdn, handle, 0);
251}
252
253int loc_service_get_id(const char *fqdn, service_id_t *handle,
254 unsigned int flags)
255{
256 async_exch_t *exch;
257
258 if (flags & IPC_FLAG_BLOCKING)
259 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
260 else {
261 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
262 if (exch == NULL)
263 return errno;
264 }
265
266 ipc_call_t answer;
267 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
268 &answer);
269 sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
270
271 loc_exchange_end(exch);
272
273 if (retval != EOK) {
274 async_wait_for(req, NULL);
275 return retval;
276 }
277
278 async_wait_for(req, &retval);
279
280 if (retval != EOK) {
281 if (handle != NULL)
282 *handle = (service_id_t) -1;
283
284 return retval;
285 }
286
287 if (handle != NULL)
288 *handle = (service_id_t) IPC_GET_ARG1(answer);
289
290 return retval;
291}
292
293/** Get service name.
294 *
295 * Provided ID of a service, return its name.
296 *
297 * @param svc_id Service ID
298 * @param name Place to store pointer to new string. Caller should
299 * free it using free().
300 * @return EOK on success or negative error code
301 */
302int loc_service_get_name(service_id_t svc_id, char **name)
303{
304 async_exch_t *exch;
305 char name_buf[LOC_NAME_MAXLEN + 1];
306 ipc_call_t dreply;
307 size_t act_size;
308 sysarg_t dretval;
309
310 *name = NULL;
311 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
312
313 ipc_call_t answer;
314 aid_t req = async_send_1(exch, LOC_SERVICE_GET_NAME, svc_id, &answer);
315 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
316 &dreply);
317 async_wait_for(dreq, &dretval);
318
319 loc_exchange_end(exch);
320
321 if (dretval != EOK) {
322 async_wait_for(req, NULL);
323 return dretval;
324 }
325
326 sysarg_t retval;
327 async_wait_for(req, &retval);
328
329 if (retval != EOK)
330 return retval;
331
332 act_size = IPC_GET_ARG2(dreply);
333 assert(act_size <= LOC_NAME_MAXLEN);
334 name_buf[act_size] = '\0';
335
336 *name = str_dup(name_buf);
337 if (*name == NULL)
338 return ENOMEM;
339
340 return EOK;
341}
342
343
344int loc_namespace_get_id(const char *name, service_id_t *handle,
345 unsigned int flags)
346{
347 async_exch_t *exch;
348
349 if (flags & IPC_FLAG_BLOCKING)
350 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
351 else {
352 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
353 if (exch == NULL)
354 return errno;
355 }
356
357 ipc_call_t answer;
358 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
359 &answer);
360 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
361
362 loc_exchange_end(exch);
363
364 if (retval != EOK) {
365 async_wait_for(req, NULL);
366 return retval;
367 }
368
369 async_wait_for(req, &retval);
370
371 if (retval != EOK) {
372 if (handle != NULL)
373 *handle = (service_id_t) -1;
374
375 return retval;
376 }
377
378 if (handle != NULL)
379 *handle = (service_id_t) IPC_GET_ARG1(answer);
380
381 return retval;
382}
383
384/** Get category ID.
385 *
386 * Provided name of a category, return its ID.
387 *
388 * @param name Category name
389 * @param cat_id Place to store ID
390 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
391 * @return EOK on success or negative error code
392 */
393int loc_category_get_id(const char *name, category_id_t *cat_id,
394 unsigned int flags)
395{
396 async_exch_t *exch;
397
398 if (flags & IPC_FLAG_BLOCKING)
399 exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
400 else {
401 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
402 if (exch == NULL)
403 return errno;
404 }
405
406 ipc_call_t answer;
407 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
408 &answer);
409 sysarg_t retval = async_data_write_start(exch, name, str_size(name));
410
411 loc_exchange_end(exch);
412
413 if (retval != EOK) {
414 async_wait_for(req, NULL);
415 return retval;
416 }
417
418 async_wait_for(req, &retval);
419
420 if (retval != EOK) {
421 if (cat_id != NULL)
422 *cat_id = (category_id_t) -1;
423
424 return retval;
425 }
426
427 if (cat_id != NULL)
428 *cat_id = (category_id_t) IPC_GET_ARG1(answer);
429
430 return retval;
431}
432
433
434loc_object_type_t loc_id_probe(service_id_t handle)
435{
436 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
437
438 sysarg_t type;
439 int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
440
441 loc_exchange_end(exch);
442
443 if (retval != EOK)
444 return LOC_OBJECT_NONE;
445
446 return (loc_object_type_t) type;
447}
448
449async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
450 unsigned int flags)
451{
452 async_sess_t *sess;
453
454 if (flags & IPC_FLAG_BLOCKING)
455 sess = service_connect_blocking(mgmt, SERVICE_LOC,
456 LOC_CONNECT_TO_SERVICE, handle);
457 else
458 sess = service_connect(mgmt, SERVICE_LOC,
459 LOC_CONNECT_TO_SERVICE, handle);
460
461 return sess;
462}
463
464int loc_null_create(void)
465{
466 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
467
468 sysarg_t null_id;
469 int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
470
471 loc_exchange_end(exch);
472
473 if (retval != EOK)
474 return -1;
475
476 return (int) null_id;
477}
478
479void loc_null_destroy(int null_id)
480{
481 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
482 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
483 loc_exchange_end(exch);
484}
485
486static size_t loc_count_namespaces_internal(async_exch_t *exch)
487{
488 sysarg_t count;
489 int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
490 if (retval != EOK)
491 return 0;
492
493 return count;
494}
495
496/** Add service to category.
497 *
498 * @param svc_id Service ID
499 * @param cat_id Category ID
500 * @return EOK on success or negative error code
501 */
502int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
503{
504 async_exch_t *exch;
505 sysarg_t retval;
506
507 exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
508 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
509 loc_exchange_end(exch);
510
511 return retval;
512}
513
514static size_t loc_count_services_internal(async_exch_t *exch,
515 service_id_t ns_handle)
516{
517 sysarg_t count;
518 int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
519 &count);
520 if (retval != EOK)
521 return 0;
522
523 return count;
524}
525
526size_t loc_count_namespaces(void)
527{
528 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
529 size_t size = loc_count_namespaces_internal(exch);
530 loc_exchange_end(exch);
531
532 return size;
533}
534
535size_t loc_count_services(service_id_t ns_handle)
536{
537 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
538 size_t size = loc_count_services_internal(exch, ns_handle);
539 loc_exchange_end(exch);
540
541 return size;
542}
543
544size_t loc_get_namespaces(loc_sdesc_t **data)
545{
546 /* Loop until read is succesful */
547 while (true) {
548 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
549 size_t count = loc_count_namespaces_internal(exch);
550 loc_exchange_end(exch);
551
552 if (count == 0)
553 return 0;
554
555 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
556 if (devs == NULL)
557 return 0;
558
559 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
560
561 ipc_call_t answer;
562 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
563 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
564
565 loc_exchange_end(exch);
566
567 if (rc == EOVERFLOW) {
568 /*
569 * Number of namespaces has changed since
570 * the last call of LOC_GET_NAMESPACE_COUNT
571 */
572 free(devs);
573 continue;
574 }
575
576 if (rc != EOK) {
577 async_wait_for(req, NULL);
578 free(devs);
579 return 0;
580 }
581
582 sysarg_t retval;
583 async_wait_for(req, &retval);
584
585 if (retval != EOK)
586 return 0;
587
588 *data = devs;
589 return count;
590 }
591}
592
593size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
594{
595 /* Loop until read is succesful */
596 while (true) {
597 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
598 size_t count = loc_count_services_internal(exch, ns_handle);
599 loc_exchange_end(exch);
600
601 if (count == 0)
602 return 0;
603
604 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
605 if (devs == NULL)
606 return 0;
607
608 exch = loc_exchange_begin(LOC_PORT_CONSUMER);
609
610 ipc_call_t answer;
611 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
612 int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
613
614 loc_exchange_end(exch);
615
616 if (rc == EOVERFLOW) {
617 /*
618 * Number of services has changed since
619 * the last call of LOC_GET_SERVICE_COUNT
620 */
621 free(devs);
622 continue;
623 }
624
625 if (rc != EOK) {
626 async_wait_for(req, NULL);
627 free(devs);
628 return 0;
629 }
630
631 sysarg_t retval;
632 async_wait_for(req, &retval);
633
634 if (retval != EOK)
635 return 0;
636
637 *data = devs;
638 return count;
639 }
640}
641
642static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
643 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
644{
645 async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
646
647 ipc_call_t answer;
648 aid_t req = async_send_1(exch, method, arg1, &answer);
649 int rc = async_data_read_start(exch, id_buf, buf_size);
650
651 loc_exchange_end(exch);
652
653 if (rc != EOK) {
654 async_wait_for(req, NULL);
655 return rc;
656 }
657
658 sysarg_t retval;
659 async_wait_for(req, &retval);
660
661 if (retval != EOK) {
662 return retval;
663 }
664
665 *act_size = IPC_GET_ARG1(answer);
666 return EOK;
667}
668
669/** Get list of IDs.
670 *
671 * Returns an allocated array of service IDs.
672 *
673 * @param method IPC method
674 * @param arg1 IPC argument 1
675 * @param data Place to store pointer to array of IDs
676 * @param count Place to store number of IDs
677 * @return EOK on success or negative error code
678 */
679static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
680 sysarg_t **data, size_t *count)
681{
682 service_id_t *ids;
683 size_t act_size;
684 size_t alloc_size;
685 int rc;
686
687 *data = NULL;
688 act_size = 0; /* silence warning */
689
690 rc = loc_category_get_ids_once(method, arg1, NULL, 0,
691 &act_size);
692 if (rc != EOK)
693 return rc;
694
695 alloc_size = act_size;
696 ids = malloc(alloc_size);
697 if (ids == NULL)
698 return ENOMEM;
699
700 while (true) {
701 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
702 &act_size);
703 if (rc != EOK)
704 return rc;
705
706 if (act_size <= alloc_size)
707 break;
708
709 alloc_size *= 2;
710 free(ids);
711
712 ids = malloc(alloc_size);
713 if (ids == NULL)
714 return ENOMEM;
715 }
716
717 *count = act_size / sizeof(category_id_t);
718 *data = ids;
719 return EOK;
720}
721
722/** Get list of services in category.
723 *
724 * Returns an allocated array of service IDs.
725 *
726 * @param cat_id Category ID
727 * @param data Place to store pointer to array of IDs
728 * @param count Place to store number of IDs
729 * @return EOK on success or negative error code
730 */
731int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
732 size_t *count)
733{
734 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
735 data, count);
736}
737
738/** Get list of categories.
739 *
740 * Returns an allocated array of category IDs.
741 *
742 * @param data Place to store pointer to array of IDs
743 * @param count Place to store number of IDs
744 * @return EOK on success or negative error code
745 */
746int loc_get_categories(category_id_t **data, size_t *count)
747{
748 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
749 data, count);
750}
Note: See TracBrowser for help on using the repository browser.