diff options
Diffstat (limited to 'libhurd-cap-server')
31 files changed, 0 insertions, 5772 deletions
diff --git a/libhurd-cap-server/ChangeLog b/libhurd-cap-server/ChangeLog deleted file mode 100644 index db21a71..0000000 --- a/libhurd-cap-server/ChangeLog +++ /dev/null @@ -1,499 +0,0 @@ -2005-03-08 Neal H. Walfield <neal@gnu.org> - - * Makefile.am (libhurd_cap_server_a_SOURCES): Add ctx-cap-use.c. - * cap-server.h (struct hurd_cap_rpc_context): Add member HANDLE. - (struct hurd_cap_ctx_cap_use): New forward. - (hurd_cap_ctx_size): New declaration. - (hurd_cap_ctx_start_cap_use): New declaration. - (hurd_cap_ctx_end_cap_use): New declaration. - * cap-server-intern.h (struct hurd_cap_ctx_cap_use): New - structure. - * bucket-manage-mt.c (manage_demuxer): Save capability handle in - CTX->handle. - * ctx-cap-use.c: New file. - -2005-01-12 Neal H. Walfield <neal@gnu.org> - - * class-init.c (hurd_cap_class_init_untyped): Fix assert. - * bucket-manage-mt.c (manage_mt_worker): Likewise. - -2005-01-10 Bas Wijnen <shevek@fmf.nl> - - * README (TODO): Fix spelling errors. - -2005-01-07 Neal H. Walfield <neal@gnu.org> - - * class-init.c (hurd_cap_class_init_untyped): Supply the - allocate_buffer and deallocate_buffer arguments to - hurd_slab_create to conform with the new semantics. - * obj-entry-space.c (_hurd_cap_obj_entry_space): Likewise for - HURD_SLAB_SPACE_INITIALIZER. - * client-create.c (_hurd_cap_client_space): Likewise. - -2004-12-01 Neal H. Walfield <neal@gnu.org> - - * cap-server-intern.h (struct _hurd_cap_client): Fold the struct - _hurd_cap_client_entry into the struct _hurd_cap_client. - * bucket-create.c (_hurd_cap_client_death): Change all uses of - _hurd_cap_client_entry_t to use the merged _hurd_cap_client_t. - (hurd_cap_bucket_create): Likewise. - * bucket-manage-mt.c (lookup_client): Likewise. - * client-create.c (_hurd_cap_client_create): Likewise. - * client-release.c (_hurd_cap_client_release): Likewise. - -2004-12-01 Neal H. Walfield <neal@gnu.org> - - * cap-server-intern.h (_HURD_CAP_CLIENT_ID_BITS): Move from - ../hurd/types.h. Prepend underscore and update names in - definition as needed. - (_HURD_CAP_ID_BITS): Likewise. - (_HURD_CAP_CLIENT_ID_MASK): Likewise. - (_HURD_CAP_ID_MASK): Likewise. - (_hurd_cap_id_t): Likewise. - (_hurd_cap_client_id_t): Likewise. - (_hurd_cap_client_id): Likewise. - (_hurd_cap_id): Likewise. - (_hurd_cap_handle_make): Likewise. - - * bucket-inject.c (hurd_cap_bucket_inject): Update CAP_ID's type. - * bucket-manage-mt.c (lookup_client): Likewise for CLIENT_ID. - * cap-server-intern.h (struct _hurd_cap_obj_entry): Likewise for - ID. - (_hurd_cap_obj_copy_out): Likewise for CLIENT. - (struct _hurd_cap_client): Likewise for ID. - (_hurd_cap_client_release): Likewise for IDX. - * client-release.c (_hurd_cap_client_release): Likewise for IDX. - * obj-copy-out.c (_hurd_cap_obj_copy_out): Likewise for CLIENT. - -2004-12-01 Marcus Brinkmann <marcus@gnu.org> - - * client-create.c (_hurd_cap_client_constructor): Do not - initialize CLIENT->caps table here. - (_hurd_cap_client_alloc): Do not initialize CLIENT->lock, - CLIENT->state or CLIENT->pending_rpcs here. - Reported by Neal Walfield <neal@gnu.org>. - - * bucket-manage-mt.c (manage_demuxer): Rework the logic that tries - to wait until the client becomes inhibited. - Reported by Neal Walfield <neal@gnu.org>. - -2004-11-30 Neal H. Walfield <neal@gnu.org> - - * cap-server.h: Improve comments. - (hurd_cap_class_create_untyped): Tighten alignment restrictions: - ALIGNMENT must be a power of 2. - * class-init.c (hurd_cap_class_init_untyped): Calculate best - alignment. - - * cap-server.h (hurd_cap_obj_get_size): Renamed to ... - (hurd_cap_obj_user_offset): ... this. - (hurd_cap_obj_to_user_untyped): Call hurd_cap_obj_user_offset, not - hurd_cap_obj_get_size. - (hurd_cap_obj_from_user_untyped): Likewise. - * class-init.c (hurd_cap_class_init_untyped): Likewise. - - * class-create.c: Improve comments. - * obj-copy-out.c: Likewise. - -2004-11-30 Neal H. Walfield <neal@gnu.org> - - * cap-server-intern.h (_hurd_cap_obj_drop): Reverse faulty logic. - -2004-11-30 Neal H. Walfield <neal@gnu.org> - - * bucket-manage-mt.c (manage_mt_get_next_worker): If - pthread_create_from_l4_tid_np fails, return WORKER to pthread's - available thread pool. - (worker_alloc_async): Likewise. - (hurd_cap_bucket_manage_mt): Likewise. - -2004-11-30 Neal H. Walfield <neal@gnu.org> - - * bucket-manage-mt.c: Include <compiler.h>. - (manage_mt_worker): Use EXPECT_TRUE and EXPECT_FALSE rather than - __builtin_expect. Comment fixes. - (manage_mt_get_next_worker): Likewise. - (hurd_cap_bucket_manage_mt): Likewise. - * cap-server-intern.h: Include <compiler.h>. - (_hurd_cap_obj_drop): Use EXPECT_FALSE rather than - __builtin_expect. - (struct _hurd_cap_bucket): Comment fix. - * client-release.c: Include <compiler.h>. - (_hurd_cap_client_release): Use EXPECT_TRUE rather than - __builtin_expect. - -2004-11-30 Neal H. Walfield <neal@gnu.org> - - * bucket-create.c (_hurd_cap_client_death): Comparisons use ==, - not =. Fix it. - -2004-11-29 Neal H. Walfield <neal@gnu.org> - - * client-create.c (_hurd_cap_client_create): Deallocate the - gratuitous _hurd_cap_client_t, not the one we want to use. - -2004-11-01 Marcus Brinkmann <marcus@gnu.org> - - * cap-server.h (hurd_cap_class_create): Rename to ... - (hurd_cap_class_create_untyped): ... this. - (hurd_cap_class_create): New macro. - (hurd_cap_class_init): Rename to ... - (hurd_cap_class_init_untyped): ... this. - (hurd_cap_class_init): New macro. - (hurd_cap_get_obj_size): New inline function. - (hurd_cap_obj_to_user_untyped, hurd_cap_obj_from_user_untyped): - New inline function. - (hurd_cap_obj_to_user, hurd_cap_obj_from_user): New macro. - * class-alloc.c (hurd_cap_class_alloc): New variable NEW_OBJ, use - it as a temporary placeholder. - * class-create.c (hurd_cap_class_create): Rename to ... - (hurd_cap_class_create_untyped): ... this. - Use hurd_cap_class_init_untyped. - * class-init.c (hurd_cap_class_init): Rename to ... - (hurd_cap_class_init_untyped): ... this. - Add the size of struct hurd_cap_obj to SIZE. - * client-create.c (_hurd_cap_client_alloc): New variable - NEW_CLIENT, use it as a temporary placeholder. - * obj-copy-out.c (_hurd_cap_obj_copy_out): New variable NEW_ENTRY, - use it as a temporary placeholder. - - * bucket-inhibit.c (hurd_cap_bucket_end): Return something. - - * cap-server-intern.h (_hurd_cap_bucket_cond_check): Fix - assignemnt. - * table.h (hurd_table_lookup): Remove unused variable ERR. - * table.c (hurd_table_enter): Likewise. - * bucket-manage-mt.c (manage_demuxer): Remove unused variable - FROM. - (manage_mt_worker): Remove unused variable DEMUXED. - (worker_alloc_async): Remove unused variable WORKER_ITEM. Fix - assignments. - * client-release.c (_hurd_cap_client_dealloc): Remove unused - variables DONE, CURRENT_IDX. - (_hurd_cap_client_release): Remove unused variable FOUND. - -2004-10-29 Marcus Brinkmann <marcus@gnu.org> - - * cap-server.h: Include <atomic.h>. - (struct hurd_cap_obj): Change type of member refs - from unsigned int to uatomic32_t. - (hurd_cap_obj_ref): Use atomic_increment(). - (hurd_cap_obj_rele): Use atomic_decrement(). - * cap-server-intern.h (_hurd_cap_obj_drop): Remove unused variable - cap_class. Use atomic_decrement_and_test. - * obj-dealloc.c (_hurd_cap_obj_dealloc): Assert that OBJ->refs is - 0, not 1. Do not unlock the object. - -2004-10-25 Marcus Brinkmann <marcus@gnu.org> - - * Makefile.am (libhurd_cap_server_a_SOURCES): Add - bucket-worker-alloc.c. - * bucket-worker-alloc.c: New file. - * bucket-create.c (hurd_cap_bucket_create): Initialize - BUCKET->worker_alloc_sync and BUCKET->worker_alloc_state. - * cap-server-intern.h (struct _hurd_cap_bucket): New members - worker_alloc_async and worker_alloc. - * cap-server.h (hurd_cap_bucket_worker_alloc): New prototype. - * bucket-manage-mt.c (hurd_cap_bucket_manage_mt): Move - initialization of acceptor and xfer timeouts to just before the - IPC (repeat it for every IPC). Set xfer timeout to all zero. Do - not pay attention to BUCKET->free_worker after cancelling the - current worker thread at shutdown. Create a worker allocation - thread if requested, and shut it down before terminating. - (manage_mt_worker): Take a new argument, ASYNC. If it is set, add - worker thread to free list at startup, and use a timeout for the - first wait. - (manage_mt_worker_async, manage_mt_worker_sync): New wrapper - functions. - (worker_alloc_async): New function. - (manage_mt_get_next_worker): - -2004-10-23 Marcus Brinkmann <marcus@gnu.org> - - * bucket-manage-mt.c: Include <l4.h>. - (l4_xreceive, l4_xreceive_timeout): New macros. - (manage_mt_worker): Use l4_xreceive and l4_xreceive_timeout - instead l4_wait and l4_wait_timeout. - -2004-10-19 Marcus Brinkmann <marcus@gnu.org> - - * client-inhibit.c (_hurd_cap_client_resume): Lock CLIENT->lock, - not BUCKET->lock. - * obj-inhibit.c (hurd_cap_obj_resume): Lock OBJ->lock, not - CAP_CLASS->lock. - -2004-10-07 Marcus Brinkmann <marcus@gnu.org> - - * bucket-manage-mt.c (reply_err): Don't set propagation flag. - (manage_mt_worker): Clear the propagation flag. - -2004-08-02 Peter Bruin <pjbruin@dds.nl> - - * cap-server-intern.h (_hurd_cap_bucket_cond_check): Call - _hurd_cap_bucket_cond_busy instead taking its address. - -2004-04-12 Marcus Brinkmann <marcus@gnu.org> - - * bucket-manage-mt.c (manage_mt_worker): Set CTX.obj to NULL - before calling demuxer. If later on CTX.obj is not NULL, call - manage_demuxer_cleanup after sending the reply message. Set - propagation flag in message tag. - (manage_demuxer): Do not release OBJ lock before calling the - demuxer, do not acquire and release OBJ lock afterwards. Instead, - acquire a reference to OBJ. - (reply_err): Set propagation flag in message tag. - -2004-04-11 Marco Gerards <metgerards@student.han.nl> - - * table.c (hurd_table_init): Return an error code. - -2004-04-10 Marcus Brinkmann <marcus@gnu.org> - - * bucket-manage-mt.c (manage_mt_worker): Use - _hurd_cap_list_item_dequeued to set current_worker_is_us. - -2004-04-09 Marcus Brinkmann <marcus@gnu.org> - - * cap-server.h (hurd_cap_bucket_inject): Change hurd_cap_t to - hurd_cap_handle_t in R_CAP argument type. - * bucket-manage-mt.c (manage_demuxer): Likewise. - * bucket-inject.c (hurd_cap_bucket_inject): Likewise. Use - hurd_cap_handle_make instead hurd_cap_make. - - * obj-copy-out.c (_hurd_cap_obj_copy_out): Set *R_ID after adding - element. - * bucket-inject.c (hurd_cap_bucket_inject): Set *R_CAP and return 0. - -2004-04-08 Marcus Brinkmann <marcus@gnu.org> - - * bucket-inject.c, obj-copy-out.c: New files. - * Makefile.am (libhurd_cap_server_a_SOURCES): Add bucket-inject.c - and obj-copy-out.c - * bucket-create.c (hurd_cap_bucket_create): Initialize members - is_managed, nr_caps, waiting_rpcs of BUCKET. Set R_BUCKET. - * cap-server-intern.h (_hurd_cap_client_dealloc): Add new argument - BUCKET to prototype. - (struct hurd_cap_client): Remove declaration. - (struct _hurd_cap_list_item): Add new member tid. Change type for - member client to _hurd_cap_client_t. - (_hurd_cap_list_item_add, _hurd_cap_list_item_remove, - _hurd_cap_list_item_dequeued): New inline functions. - (struct _hurd_cap_obj_entry): Rename member IDX to ID. - (_hurd_cap_obj_copy_out): New prototype. - (_hurd_cap_client_create): Remove argument R_IDX from prototype. - (struct _hurd_cap_bucket): Add new members MANAGER, IS_MANAGED, - IS_MANAGER_WAITING, NR_CAPS, WAITING_RPCS, and FREE_WORKER. - (_hurd_cap_client_t): Type definition moved to ... - * cap-server.h (_hurd_cap_client_t): Here. - (struct _hurd_cap_client_t): New declaration. - (struct hurd_cap_rpc_context): Define it. - (hurd_cap_class_demux_t): Renamed to ... - (hurd_cap_class_demuxer_t): ... this. - (hurd_cap_class_create, hurd_cap_class_init): Use new type for demuxer - argument in prototype. - (hurd_cap_bucket_inject): New prototype. - * cap-server.h: Include <hurd/types.h> - * class-create (hurd_cap_class_create): Use new type for demuxer - argument. Set R_CLASS. - * class-init (hurd_cap_class_init): Use new type for demuxer argument. - * client-release.c (_hurd_cap_client_dealloc): Take new argument - BUCKET. New local variable NR_CAPS. Keep track of number of - capabilities removed. Update BUCKET->nr_caps before return. - (_hurd_cap_client_release): Pass new argument BUCKET to - _hurd_cap_client_release. - * client-create.c (_hurd_cap_client_create): Remove argument - R_IDX. Consequently, do not set R_IDX anymore. Set R_CLIENT. - Pass new argument BUCKET to _hurd_cap_client_dealloc. - * bucket-inhibit.c (hurd_cap_bucket_end): Check BUCKET->nr_caps if - FORCE flag is not set. Cancel the manager thread if needed. - (_hurd_cap_bucket_cond_busy): Move to ... - * cap-server-intern.h (_hurd_cap_bucket_cond_busy): ... here. - Add attribute always-inline. - (_hurd_cap_bucket_cond_check): New inline function. - * client-inhibit.c (_hurd_cap_client_cond_busy): Move to ... - * cap-server-intern.h (_hurd_cap_client_cond_busy): ... here. - Add attribute always-inline. - (_hurd_cap_client_cond_check): New inline function. - * class-inhibit.c (_hurd_cap_class_cond_busy): Move to ... - * cap-server-intern.h (_hurd_cap_class_cond_busy): ... here. - Add attribute always-inline. - (_hurd_cap_class_cond_check): New inline function. - * obj-inhibit.c (_hurd_cap_obj_cond_busy): Move to ... - * cap-server-intern.h (_hurd_cap_obj_cond_busy): ... here. - Add attribute always-inline. - (_hurd_cap_obj_cond_check): New inline function. - -2004-04-01 Marcus Brinkmann <marcus@gnu.org> - - * Makefile.am (libhurd_cap_server_a_SOURCES): Remove bucket-add.c, - bucket-remove.c. - * bucket-add.c, bucket-remove.c: Files removed. - * cap-server.h (hurd_cap_bucket_add, hurd_cap_bucket_remove): - Remove prototypes. - * cap-server-intern.h (struct _hurd_cap_class_entry): Removed. - (_hurd_cap_class_entry_t): Removed. - (struct _hurd_cap_bucket): Remove member classes. - * bucket-create.c (hurd_cap_bucket_create): Do not initialize - deleted member classes. - * bucket-free.c (hurd_cap_bucket_free): Do not destroy deleted - member classes. - -2004-03-26 Marcus Brinkmann <marcus@gnu.org> - - * bucket-add.c, bucket-create.c, bucket-free.c, bucket-inhibit.c, - bucket-manage-mt.c, bucket-remove.c, cap-server-intern.h, - class-free.c, class-init.c, obj-dealloc.c, obj-drop.c, - obj-entry-space.c: New files. - * Makefile.am (includehurd_HEADERS): Move table.h and task-death.h - to ... - (libhurd_cap_server_a_SOURCES): ... here. Add - cap-server-intern.h, class-init.c, class-free.c, obj-dealloc.c, - obj-drop.c, obj-entry-space.c, bucket-create.c, bucket-free.c, - bucket-add.c, bucket-remove.c, bucket-inhibit.c, - bucket-manage-mt.c. Remove class-dealloc.c. - * headers.m4: Remove table.h and task-death.h. - * cap-server.h: Include <stdbool.h>, do not include <assert.h>, - <limits.h>, <hurd/types.h>, <hurd/slab.h>, <hurd/table.h>, - <hurd/ihash.h> and <hurd/task-death.h>. - (hurd_cond_wait, struct _hurd_cap_list_item, - _hurd_cap_list_item_t, _hurd_cap_list_item_add, - _hurd_cap_list_item_remove, struct _hurd_cap_entry, - _hurd_cap_entry_t, struct hurd_cap_client, hurd_cap_client_t, - struct _hurd_cap_client_entry, _hurd_cap_client_entry_t, - _hurd_cap_class_dealloc, _hurd_cap_client_create, - hurd_cap_client_lookup, _hurd_cap_client_dealloc, - hurd_cap_client_inhibit, hurd_cap_client_resume, - _hurd_cap_client_end): Removed. - (hurd_cap_rpc_context): New declaration. - (hurd_cap_class_demux_t): New dummy type (for now). - (struct hurd_cap_class): Remove members OBJ_SIZE, CLIENT_SLAB, - CLIENT_COND, CLIENT_COND_LOCK, CLIENTS, CLIENTS_REVERSE, - CLIENT_THREADS and CLIENT_DEATH_NOTIFY. Change type of OBJ_SLAB - to struct hurd_slab_space and rename it to OBJ_SPACE. Add member - DEMUXER. Change type of member STATE to _hurd_cap_state_t. - (struct hurd_cap_obj): Add member CAP_CLASS. Change type of - member STATE to _hurd_cap_state_t. - (hurd_cap_class_create): Add arguments alignment and demuxer to - prototype. - (hurd_cap_class_init): Likewise. - (hurd_cap_class_free): New prototype. - (_hurd_cap_class_destroy): Rename to ... - (hurd_cap_class_destroy): ... this. - (hurd_cap_obj_lock, hurd_cap_obj_unlock, hurd_cap_obj_ref, - hurd_cap_obj_rele, hurd_cap_obj_drop): Remove CAP_CLASS argument. - (hurd_cap_obj_drop): Only declare prototype here. - (struct _hurd_cap_bucket): New forward declaration. - (hurd_cap_bucket_t): New typedef. - (hurd_cap_bucket_create, hurd_cap_bucket_free, - hurd_cap_bucket_add, hurd_cap_bucket_remove, - hurd_cap_bucket_manage_mt, hurd_cap_bucket_inhibit, - hurd_cap_bucket_resume, hurd_cap_bucket_end): New prototypes. - * class-alloc.c, class-create.c, class-destroy.c, class-inhibit.c, - client-create.c, client-inhibit.c, client-release.c, - obj-inhibit.c: Change the callers to take into account the above - changes. - -2004-03-25 Marcus Brinkmann <marcus@gnu.org> - - * Makefile.am (libhurd_cap_server_a_SOURCES): Add class-inhibit.c, - client-create.c, client-release.c, client-inhibit.c, and - obj-inhibit.c. - * README, class-inhibit.c, client-create.c, client-release.c, - client-inhibit.c, obj-inhibit.c: New files. - * cap-server.h: Protect inclusion with _HURD_CAP_SERVER_H. - Include <hurd/types.h>, <hurd/table.h>, <hurd/ihash.h> and - <hurd/task-death.h>. - (hurd_cond_wait): Define to pthread_cond_wait for now. - (struct _hurd_cap_list_item): New struct. - (_hurd_cap_list_item_t): New typedef. - (_hurd_cap_list_item_add, _hurd_cap_list_item_remove): New inline - functions. - (enum _hurd_cap_state): New enum. - (struct _hurd_cap_obj): Add members STATE, PENDING_RPCS, - COND_WAITER, and CLIENTS. - (hurd_cap_obj_data): Removed. - (struct _hurd_cap_entry): New struct. - (_hurd_cap_entry_t): New type. - (struct hurd_cap_client): New struct. - (hurd_cap_client_t): New type. - (struct _hurd_cap_client_entry): New struct. - (_hurd_cap_client_entry_t): New type. - (struct hurd_cap_class): Rename member SLAB to OBJ_SLAB. Add new - members OBJ_COND, OBJ_COND_LOCK, CLIENT_SLAB, CLIENT_COND, - CLIENT_COND_LOCK, CLIENT_DEATH_NOTIFY, LOCK, CLIENTS, - CLIENTS_REVERSE, STATE, COND, COND_WAITER and PENDING_RPCS. - (hurd_cap_class_init, _hurd_cap_class_destroy): New prototypes. - (hurd_cap_class_dealloc): Rename prototype to ... - (_hurd_cap_class_dealloc): ... this. - (hurd_cap_obj_lock, hurd_cap_obj_unlock): Change return type to - void. - (hurd_cap_obj_drop): Call _hurd_cap_class_dealloc (not - hurd_cap_class_dealloc). - (_hurd_cap_client_create, _hurd_cap_client_dealloc, - _hurd_cap_client_release): New prototype. - (hurd_cap_client_lookup): New inline function. - (hurd_cap_class_inhibit, hurd_cap_class_resume, - hurd_cap_client_inhibit, hurd_cap_client_resume, - _hurd_cap_client_end, hurd_cap_obj_inhibit, hurd_cap_obj_resume): - New prototypes. - * class-alloc.c (hurd_cap_class_alloc): Use CAP_CLASS->obj_slab, - not CAP_CLASS->slab. Don't check return value of - hurd_cap_obj_lock (as it is void now). - * class-create.c (_hurd_cap_obj_constructor): Initialize - OBJ->clients, OBJ->state, OBJ->pending_rpcs and OBJ->clients. - Don't check return value of pthread_mutex_destroy. - (_hurd_cap_obj_destructor): Destroy OBJ->clients. Don't check - return value of pthread_mutex_destroy. - (_hurd_cap_client_constructor, _hurd_cap_client_destructor, - _hurd_cap_client_death, hurd_cap_class_init): New functions. - (hurd_cap_class_create): Rewritten in terms of - hurd_cap_class_init. - * class-dealloc.c (hurd_cap_class_dealloc): Rename to ... - (_hurd_cap_class_dealloc): ... this. Do not check return value of - now void hurd_cap_obj_unlock function. Assert OBJ->state and - OBJ->pending_rpcs. Use CAP_CLASS->obj_slab, not CAP_CLASS->slab. - * class-destroy.c: Do not include <assert.h>. - (_hurd_cap_client_try_destroy): New function. - (hurd_cap_class_destroy): Rewritten. - (hurd_cap_class_free): New function. - - * task-death.h (task_death_notify_t): Fix return type (should be - void, not void *). - -2004-03-23 Marcus Brinkmann <marcus@gnu.org> - - * Makefile.am (includehurd_HEADERS): Add table.h and task-death.h. - (libhurd_cap_server_a_SOURCES): Add task-death.c, remove table.h. - * task-death.h, task-death.c: New files. - * headers.m4: Add task-death.h. - - * table.h (_HURD_TABLE_ALIGN): New macro. - (HURD_TABLE_INITIALIZER): Use it for ENTRY_SIZE. - - * Makefile.am (AM_CFLAGS): New variable. - * headers.m4: Add table.h. - * table.h (hurd_table_entry_t): Type removed. - (struct hurd_table): Change type of DATA to char *. New member - ENTRY_SIZE. - (HURD_TABLE_INITIALIZER): Take argument SIZE_OF_ONE. Initialize - ENTRY_SIZE. - (hurd_table_init): Add new argument ENTRY_SIZE to prototype. - (hurd_table_enter): Change type of DATA to void *. - (hurd_table_lookup): Change return type to void *. Return 0, not - HURD_TABLE_EMPTY. Reimplement for new semantics. - * table.c: Include <assert.h>. - (hurd_table_init): Add new argument ENTRY_SIZE. Pass it to - HURD_TABLE_INITIALIZER. - (hurd_table_enter): Use TABLE->entry_size for reallocation. - Adjust code to fit new semantics. Add 1 to TABLE->first_free to - make that point to the element after the one we just added. - - * Makefile.am (libhurd_cap_server_a_SOURCES): Add table.h, table.c. - * table.h, table.c: New files. - -2004-03-21 Marcus Brinkmann <marcus@gnu.org> - - * cap-server.h (hurd_cap_obj_rele): Require at least two - references. - - * Initial release. diff --git a/libhurd-cap-server/Makefile.am b/libhurd-cap-server/Makefile.am deleted file mode 100644 index 1d0c400..0000000 --- a/libhurd-cap-server/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ -# Makefile.am - Makefile template for libhurd-cap-server. -# Copyright (C) 2004, 2005 Free Software Foundation, Inc. -# Written by Marcus Brinkmann. -# -# This file is part of the GNU Hurd. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the Free -# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# 02111-1307 USA. - -lib_LIBRARIES = libhurd-cap-server.a - -includehurddir = $(includedir)/hurd -includehurd_HEADERS = cap-server.h - -# FIXME: Build a special libhurd-ihash.a using libc-parts for the rootservers, -# and a normal for everybody else. -AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/libc-parts -AM_CFLAGS = -std=gnu99 -libhurd_cap_server_a_SOURCES = table.h table.c \ - task-death.h task-death.c \ - cap-server-intern.h class-init.c class-create.c \ - class-destroy.c class-free.c \ - class-alloc.c class-inhibit.c \ - obj-dealloc.c obj-drop.c obj-inhibit.c \ - obj-entry-space.c obj-copy-out.c \ - client-create.c client-release.c client-inhibit.c \ - bucket-create.c bucket-free.c bucket-inhibit.c \ - bucket-manage-mt.c bucket-worker-alloc.c bucket-inject.c \ - ctx-cap-use.c diff --git a/libhurd-cap-server/README b/libhurd-cap-server/README deleted file mode 100644 index ce19f55..0000000 --- a/libhurd-cap-server/README +++ /dev/null @@ -1,185 +0,0 @@ -TODO: - -* Keep track of number of allocated capabilities or otherwise enable - to check if a bucket is still in use!!! (so at least a per-client - count is required). -* Implement bucket-inhibit correctly. !!! Also see: -* Decide if it is needed to allow capability allocation - outside of RPCs (as return arguments). In that case, allocation - must be blocked while it is checked if no extinct users exists - - otherwise inhibiting RPCs is good enough. -* Verify all the bucket/client stuff after rewrite. - -* Do we need to support soft references? -* Extend table and hash interface to reclaim resources without - reinitialization. !! -* table.h/table.c should take alignment. - -An introduction to the capability system, server side. ------------------------------------------------------- - -A server provides services to its clients. In a capability system the -right to access a given service is called a capability. This right is -held by a client. It was previously granted to the client by the -server. The client can then make use of this right, cease it, or -transfer (copy) it to a new client. - -The capability system is object oriented. This means that the -services granted by the server are represented by remote procedure -calls (RPCs) invoked on server-side objects. A capability thus -represents the right to invoke an (arbitrary) RPC on any given object. - -The Hurd capability system provides a flexible, yet efficient way, for -servers to implement services for different types of objects to many -users. - -The server-side objects (capability objects) are organized in -capability classes. All capability objects in one class have the same -basic type. Of course, the implementation of the server is free to -make further distinctions among the objects in one class. But the -implementation of the capability library makes certain assumptions -about classes, and some operations always affect all objects in one -class. Furthermore, all objects in one class share certain -ressources. Thus, a capability class is an important organizational -structure. - -For example, all open files in a file server can be implemented as one -capability class. Another capability class could be used for all -filesystem control capabilities. - - -Capability Objects ------------------- - -Any server-side object you want to receive RPCs on is represented by a -capability object. Clients are then granted access to capability -objects, which means that they are allowed to invoke RPCs on such -objects (see "Capabilities"). - -All capability objects have the same basic storage size, use the same -constructors and destructors, and are cached in the same slab -allocator. Capability objects have their own lock and reference -counter. The lock and reference counter are embedded at the start of -your own definition of what a capability object should contain: - - struct my_cap - { - struct hurd_cap_obj obj; - - int my_own_data; - ... - }; - - -Capability objects are cached objects. They are cached in the slab -allocator provided by libhurd-slab. This improves processor cache -usage and allows pre-allocation, and makes it possible to keep some -state even across object life time. The life-time of a capability -object, and the meaning of the various constructors and destructors, -can be seen in the following diagram: - - 1. Object is constructed in the cache OBJ_INIT - 2.1. Object is instantiated and removed from the free list OBJ_ALLOC - 2.2. Object is deallocated and put back on the free list OBJ_REINIT - 3. Object is destroyed and removed from the cache OBJ_DESTROY - - Note that step 2 can occur several times, or not at all. - This is the state diagram for each object: - - START ==(1.)== OBJ_INIT --(3.)--> OBJ_DESTROY = END - | ^ - | | - (2.1.) (3.) - | | - v | - OBJ_ALLOC -(2.2.)--> OBJ_REINIT - ^ | - | | - +-------(2.1.)-------+ - -Capability objects are constructed and initialized in bursts whenever -a new slab page is allocated for the cache. For this purpose, the -OBJ_INIT callback is invoked. If the object is used, further -per-instantiation initialization can be performed by OBJ_ALLOC. Each -time this happens, the OBJ_REINIT callback is invoked when the object -becomes deallocated and is returned to the cache. At the end of each -objects lifetime, when the cache page is destroyed, for example due to -memory pressure, or because the capability class is destroyed, the -destructor callback OBJ_DESTROY is called. - -OBJ_ALLOC is provided because some resources may not be suitable for -caching. In particular, OBJ_REINIT must not fail, so any resources -that can not be safely (ie without errors) reverted to their -initialized state are not suitable for caching and must be allocated -with OBJ_ALLOC and destroyed with OBJ_REINIT. - -After having defined your own capability objects, you can create a -capability class from these objects. A capability class is a complex -structure that allows to grant access to capability objects to users, -and process the incoming RPCs. - - -Capability Classes ------------------- - -Capability classes require a capability object definition (via storage -size and constructor/destructor callbacks), and a demuxer for -incoming RPC messages on capability objects from this class. - -After creating a class, you will usually want to start a manager -thread and call one of the RPC manage functions (multi-threaded or -single-threaded). The manage function starts processing incoming RPCs -immediately. You can provide a timeout or let it run indefinitely. -If you specify a timeout, the manage function will exit if there are -no active client connections for a certain time. - -You can also inhibit all RPCs on a class, from the outside or from an -RPC handler. This will cancel all pending operations (except the -calling one), and prevents any more messages from being processed. -Incoming RPCs are blocked (FIXME: except interrupt_rpc). - -To prevent DoS attacks, only one RPC per client thread at any time is -allowed. - - -Clients -------- - -Each client gets a capability ID name space. In this name space, -references for capability objects are kept. If a capability object -gets revoked, the references become stale. - - -Server Loop ------------ - -FIXME: Should inhibit class block the server manager thread, or only -worker threads? The former is resource lighter, the other allows to -process interrupt messages to interrupt the operation blocking the -class. - -Worker Thread Operation ------------------------ - -0. Lock cap_class for most of the following. If necessary, first - block until class state is green. -1. Check cap_class->client_threads if that client is already in an RPC. - If yes, drop the message. -2. Is this a proper RPC? If not, it might be an initial handshake request. - If it is an initial handshake request, lookup the task ID in - cap_class->clients_reverse, and if it doesn't exist, add it and return. - Otherwise proceed. -3. Lookup the provided client id in the table cap_class->clients - (range checked), adding a reference. If not found, drop the message. -4. Add yourself to cap_class->pending_rpcs. -5. Unlock the cap_class, and lock the client. If necessary, first - block until client state is green. -6. Lookup the capability id, adding an internal reference. If not - found, drop the message. -7. FIXME: Handle external references and reference container - transactions here. Otherwise, proceed: -8. Add ourselves to client->pending_rpcs. Unlock the client, lock the - capability object. If necessary, first block until cap obj state is green, -9. Add yourself to cap_obj->pending_rpcs. -10. Process RPC. -11. FIXME: Reverse the whole funky business. diff --git a/libhurd-cap-server/bucket-create.c b/libhurd-cap-server/bucket-create.c deleted file mode 100644 index e79091c..0000000 --- a/libhurd-cap-server/bucket-create.c +++ /dev/null @@ -1,176 +0,0 @@ -/* bucket-create.c - Create a capability bucket. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> -#include <assert.h> -#include <pthread.h> - -#include "cap-server-intern.h" - - -/* Process the task death event for TASK_ID. */ -static void -_hurd_cap_client_death (void *hook, hurd_task_id_t task_id) -{ - hurd_cap_bucket_t bucket = (hurd_cap_bucket_t) hook; - _hurd_cap_client_t client; - - pthread_mutex_lock (&bucket->lock); - client = (_hurd_cap_client_t) hurd_ihash_find (&bucket->clients_reverse, - task_id); - if (client) - { - /* Found it. We will consume the "client is still living" - reference, which can only be removed by us. As client death - notifications are fully serialized, we don't need to take an - extra reference now. However, we must mark the client entry - as dead, so that no further references are acquired by - anybody else. */ - client->dead = 1; - } - pthread_mutex_unlock (&bucket->lock); - - if (client) - { - error_t err; - - /* Inhibit all RPCs on this client. This can only fail if we - are canceled. However, we are the task death manager thread, - and nobody should cancel us. (FIXME: If it turns out that we - can be canceled, we should just return on error). */ - err = _hurd_cap_client_inhibit (bucket, client); - assert (!err); - - /* End RPCs on this client. There shouldn't be any (the client - is dead), but due to small races, there is a slight chance we - still have a worker thread blocked on an incoming message - from the now dead client task. */ - _hurd_cap_client_end (bucket, client); - -#ifndef NDEBUG - pthread_mutex_lock (&bucket->lock); - /* Now, we should have the last reference for this client. */ - assert (client->refs == 1); - pthread_mutex_unlock (&bucket->lock); -#endif - - /* Release our, the last, reference and deallocate all - resources, most importantly this will remove us from the - client table of the class and release the task info - capability. */ - _hurd_cap_client_release (bucket, client->id); - } -} - - -/* Create a new bucket and return it in R_BUCKET. */ -error_t -hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket) -{ - error_t err; - hurd_cap_bucket_t bucket; - - bucket = malloc (sizeof (struct _hurd_cap_bucket)); - if (!bucket) - return errno; - - - /* Client management. */ - - err = pthread_cond_init (&bucket->client_cond, NULL); - if (err) - goto err_client_cond; - - err = pthread_mutex_init (&bucket->client_cond_lock, NULL); - if (err) - goto err_client_cond_lock; - - /* The client death notifications will be requested when we start to - serve RPCs on the bucket. */ - - /* Bucket management. */ - - err = pthread_mutex_init (&bucket->lock, NULL); - if (err) - goto err_lock; - - bucket->is_managed = false; - bucket->state = _HURD_CAP_STATE_GREEN; - - err = pthread_cond_init (&bucket->cond, NULL); - if (err) - goto err_cond; - - /* The member cond_waiter will be initialized when the state changes - to _HURD_CAP_STATE_YELLOW. */ - - bucket->nr_caps = 0; - bucket->pending_rpcs = NULL; - bucket->waiting_rpcs = NULL; - - hurd_ihash_init (&bucket->senders, - offsetof (struct _hurd_cap_list_item, locp)); - - err = hurd_table_init (&bucket->clients, - sizeof (_hurd_cap_client_t)); - if (err) - goto err_clients; - - hurd_ihash_init (&bucket->clients_reverse, - offsetof (struct _hurd_cap_client, locp)); - - /* Do not use asynchronous thread allocation by default. */ - bucket->is_worker_alloc_async = false; - /* We have to leave bucket->worker_alloc uninitialized. That field - and bucket->worker_alloc_state will be initialized if - asynchronous worker thread allocation is used. */ - - /* Finally, add the notify handler. */ - bucket->client_death_notify.notify_handler = _hurd_cap_client_death; - bucket->client_death_notify.hook = bucket; - hurd_task_death_notify_add (&bucket->client_death_notify); - - *r_bucket = bucket; - return 0; - -#if 0 - /* Provided here in case more error cases are added. */ - hurd_table_destroy (&bucket->clients); -#endif - - err_clients: - pthread_cond_destroy (&bucket->cond); - err_cond: - pthread_mutex_destroy (&bucket->lock); - err_lock: - pthread_mutex_destroy (&bucket->client_cond_lock); - err_client_cond_lock: - pthread_cond_destroy (&bucket->client_cond); - err_client_cond: - free (bucket); - - return err; -} diff --git a/libhurd-cap-server/bucket-free.c b/libhurd-cap-server/bucket-free.c deleted file mode 100644 index 5793114..0000000 --- a/libhurd-cap-server/bucket-free.c +++ /dev/null @@ -1,47 +0,0 @@ -/* bucket-create.c - Create a capability bucket. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> -#include <assert.h> -#include <pthread.h> - -#include "cap-server-intern.h" - - -/* Free the bucket BUCKET, which must not be used. */ -void -hurd_cap_bucket_free (hurd_cap_bucket_t bucket) -{ - /* FIXME: Add some assertions to ensure it is not used. - Reintroduce _hurd_cap_client_try_destroy. */ - hurd_table_destroy (&bucket->clients); - pthread_cond_destroy (&bucket->cond); - pthread_mutex_destroy (&bucket->lock); - pthread_mutex_destroy (&bucket->client_cond_lock); - pthread_cond_destroy (&bucket->client_cond); - free (bucket); -} - diff --git a/libhurd-cap-server/bucket-inhibit.c b/libhurd-cap-server/bucket-inhibit.c deleted file mode 100644 index b3484bf..0000000 --- a/libhurd-cap-server/bucket-inhibit.c +++ /dev/null @@ -1,142 +0,0 @@ -/* bucket-inhibit.c - Inhibit RPCs on a capability bucket. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Inhibit all RPCs on the capability bucket BUCKET (which must not - be locked). You _must_ follow up with a hurd_cap_bucket_resume - operation, and hold at least one reference to the object - continuously until you did so. */ -error_t -hurd_cap_bucket_inhibit (hurd_cap_bucket_t bucket) -{ - error_t err; - - pthread_mutex_lock (&bucket->lock); - - /* First wait until any other inhibitor has resumed the bucket. If - this function is called within an RPC, we are going to be - canceled anyway. Otherwise, it ensures that bucket inhibitions - are fully serialized (per bucket). */ - /* FIXME: Do something if the state is _HURD_CAP_STATE_BLACK? Can - only happen if we are called from outside any RPCs. */ - while (bucket->state != _HURD_CAP_STATE_GREEN) - { - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - if (err) - { - /* We have been canceled. */ - pthread_mutex_unlock (&bucket->lock); - return err; - } - } - - /* Now it is our turn to inhibit the bucket. */ - bucket->cond_waiter = pthread_self (); - - if (_hurd_cap_bucket_cond_busy (bucket)) - { - _hurd_cap_list_item_t pending_rpc = bucket->pending_rpcs; - - /* There are still pending RPCs (beside us). Cancel them. */ - while (pending_rpc) - { - if (pending_rpc->thread != bucket->cond_waiter) - pthread_cancel (pending_rpc->thread); - pending_rpc = pending_rpc->next; - } - - /* Indicate that we would like to know when they have gone. */ - bucket->state = _HURD_CAP_STATE_YELLOW; - - /* The last one will shut the door. */ - do - { - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - if (err) - { - /* We have been canceled ourselves. Give up. */ - bucket->state = _HURD_CAP_STATE_GREEN; - pthread_mutex_unlock (&bucket->lock); - return err; - } - } - while (bucket->state != _HURD_CAP_STATE_RED); - } - else - bucket->state = _HURD_CAP_STATE_RED; - - /* Now all pending RPCs have been canceled and are completed (except - us), and all incoming RPCs are inhibited. */ - pthread_mutex_unlock (&bucket->lock); - - return 0; -} - - -/* Resume RPCs on the bucket BUCKET and wake-up all waiters. */ -void -hurd_cap_bucket_resume (hurd_cap_bucket_t bucket) -{ - pthread_mutex_lock (&bucket->lock); - - bucket->state = _HURD_CAP_STATE_GREEN; - - /* Broadcast the change to all potential waiters. */ - pthread_cond_broadcast (&bucket->cond); - - pthread_mutex_unlock (&bucket->lock); -} - - -/* End management of the bucket BUCKET. */ -error_t -hurd_cap_bucket_end (hurd_cap_bucket_t bucket, bool force) -{ - pthread_mutex_lock (&bucket->lock); - - if (!force && bucket->nr_caps) - { - pthread_mutex_unlock (&bucket->lock); - return EBUSY; - } - - bucket->state = _HURD_CAP_STATE_BLACK; - - /* Broadcast the change to all potential waiters. */ - pthread_cond_broadcast (&bucket->cond); - - if (bucket->is_managed && bucket->cond_waiter != bucket->manager) - pthread_cancel (bucket->manager); - - pthread_mutex_unlock (&bucket->lock); - - return 0; -} diff --git a/libhurd-cap-server/bucket-inject.c b/libhurd-cap-server/bucket-inject.c deleted file mode 100644 index 0a81b27..0000000 --- a/libhurd-cap-server/bucket-inject.c +++ /dev/null @@ -1,58 +0,0 @@ -/* bucket-inject.c - Copy out a capability to a client. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Copy out a capability for the capability OBJ to the client with the - task ID TASK_ID. Returns the capability (valid only for this user) - in *R_CAP, or an error. It is not safe to call this from outside - an RPC on OBJ while the manager is running. */ -error_t -hurd_cap_bucket_inject (hurd_cap_bucket_t bucket, hurd_cap_obj_t obj, - hurd_task_id_t task_id, hurd_cap_handle_t *r_cap) -{ - error_t err; - _hurd_cap_client_t client; - _hurd_cap_id_t cap_id; - - err = _hurd_cap_client_create (bucket, task_id, &client); - if (err) - return err; - - pthread_mutex_lock (&obj->lock); - err = _hurd_cap_obj_copy_out (obj, bucket, client, &cap_id); - pthread_mutex_unlock (&obj->lock); - _hurd_cap_client_release (bucket, client->id); - if (err) - return err; - - *r_cap = _hurd_cap_handle_make (client->id, cap_id); - return 0; -} diff --git a/libhurd-cap-server/bucket-manage-mt.c b/libhurd-cap-server/bucket-manage-mt.c deleted file mode 100644 index 15de1f1..0000000 --- a/libhurd-cap-server/bucket-manage-mt.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* bucket-manage-mt.c - Manage RPCs on a bucket. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> -#include <assert.h> -#include <stdint.h> -#include <pthread.h> - -#include <l4.h> -#include <compiler.h> - -#include "cap-server-intern.h" - - -/* When using propagation, the from thread ID returned can differ from - the one we used for the closed receive. */ -#define l4_xreceive_timeout(from,timeout,fromp) \ - (l4_ipc (l4_nilthread, from, timeout, fromp)) -#define l4_xreceive(from,fromp) \ - l4_xreceive_timeout (from, l4_timeouts (L4_ZERO_TIME, L4_NEVER), fromp) - - -/* FIXME: Throughout this file, for debugging, the behaviour could be - relaxed to return errors to callers which would otherwise be - ignored (due to malformed requests etc). */ - - -/* FIXME: This section contains a lot of random junk that maybe should - be somewhere else (or not). */ - -/* Cancel the pending RPC of the specified thread. */ -#define HURD_CAP_MSG_LABEL_CANCEL 0x100 -#define HURD_CAP_MSG_LABEL_GET_ROOT 0x101 - -/* Some error for this. */ -#define ECAP_NOREPLY 0x10001 -#define ECAP_DIED 0x10002 - - -/* The msg labels of the reply from the worker to the manager. */ -#define _HURD_CAP_MSG_WORKER_ACCEPTED 0 -#define _HURD_CAP_MSG_WORKER_REJECTED 1 - -struct worker_info -{ - /* The bucket. */ - hurd_cap_bucket_t bucket; - - /* The manager thread. */ - l4_thread_id_t manager_tid; - - /* The timeout for the worker thread as an L4 time period. */ - l4_time_t timeout; -}; - - -static void -__attribute__((always_inline)) -reply_err (l4_thread_id_t to, error_t err) -{ -#define HURD_L4_ERROR_LABEL ((uint16_t) INT16_MIN) -#define HURD_L4_ERROR_TAG ((HURD_L4_ERROR_LABEL << 16) & 1) - l4_msg_tag_t tag = HURD_L4_ERROR_TAG; - - l4_set_msg_tag (tag); - l4_load_mr (1, err); - l4_reply (to); -} - - -/* Lookup the client with client ID CLIENT_ID and return it in - *R_CLIENT with one reference for the entry in the bucket. It is - verified that the client is in fact the one with the task ID - TASK_ID. */ -static error_t -__attribute__((always_inline)) -lookup_client (hurd_cap_bucket_t bucket, _hurd_cap_client_id_t client_id, - hurd_task_id_t task_id, _hurd_cap_client_t *r_client) -{ - error_t err = 0; - _hurd_cap_client_t *clientp; - - pthread_mutex_lock (&bucket->lock); - /* Look up the client by its ID. */ - clientp = hurd_table_lookup (&bucket->clients, client_id); - if (!clientp || (*clientp)->dead || (*clientp)->task_id != task_id) - err = ECAP_NOREPLY; - else - { - (*clientp)->refs++; - *r_client = *clientp; - } - pthread_mutex_unlock (&bucket->lock); - - return err; -} - - -/* Process the message CTX->MSG from thread CTX->FROM in worker thread - CTX->WORKER of bucket CTX->BUCKET. Return ECAP_NOREPLY if no reply - should be sent. Any other error will be replied to the user. If 0 - is returned, CTX->MSG must contain the reply message. */ -static error_t -__attribute__((always_inline)) -manage_demuxer (hurd_cap_rpc_context_t ctx, _hurd_cap_list_item_t worker) -{ - error_t err = 0; - hurd_cap_bucket_t bucket = ctx->bucket; - _hurd_cap_client_t client; - hurd_cap_class_t cap_class; - hurd_cap_obj_t obj; - _hurd_cap_obj_entry_t obj_entry; - struct _hurd_cap_list_item worker_client; - struct _hurd_cap_list_item worker_class; - struct _hurd_cap_list_item worker_obj; - - worker_client.thread = worker->thread; - worker_client.tid = worker->tid; - worker_client.next = NULL; - worker_client.prevp = NULL; - - worker_class = worker_client; - worker_obj = worker_client; - - if (l4_msg_label (ctx->msg) == HURD_CAP_MSG_LABEL_GET_ROOT) - { - /* This is the "get the root capability" RPC. FIXME: Needs to - be implemented. */ - return ENOSYS; - } - - /* Every normal RPC must have at least one untyped word, which - contains the client and capability ID. Otherwise the message is - malformed, and thus ignored. */ - if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) < 1) - return ECAP_NOREPLY; - ctx->handle = l4_msg_word (ctx->msg, 0); - - err = lookup_client (bucket, _hurd_cap_client_id (ctx->handle), - ctx->sender, &client); - if (err) - return err; - - /* At this point, CLIENT_ID and CLIENT are valid, and we have one - reference for the client. */ - - pthread_mutex_lock (&client->lock); - /* First, we have to check if the class is inhibited, and if it is, - we have to wait until it is uninhibited. */ - if (EXPECT_FALSE (client->state == _HURD_CAP_STATE_BLACK)) - err = ECAP_NOREPLY; - else if (EXPECT_FALSE (client->state != _HURD_CAP_STATE_GREEN)) - { - pthread_mutex_unlock (&client->lock); - pthread_mutex_lock (&bucket->client_cond_lock); - pthread_mutex_lock (&client->lock); - while (!err && client->state != _HURD_CAP_STATE_GREEN) - { - if (client->state == _HURD_CAP_STATE_BLACK) - err = ECAP_NOREPLY; - else - { - pthread_mutex_unlock (&client->lock); - err = hurd_cond_wait (&bucket->client_cond, - &bucket->client_cond_lock); - pthread_mutex_lock (&client->lock); - } - } - pthread_mutex_unlock (&bucket->client_cond_lock); - } - if (err) - { - pthread_mutex_unlock (&client->lock); - /* Either the client died, or we have been canceled. */ - _hurd_cap_client_release (bucket, client->id); - return err; - } - - { - _hurd_cap_obj_entry_t *entry; - - entry = (_hurd_cap_obj_entry_t *) - hurd_table_lookup (&client->caps, _hurd_cap_id (ctx->handle)); - if (!entry) - err = ECAP_NOREPLY; - else - { - obj_entry = *entry; - - if (EXPECT_FALSE (!obj_entry->external_refs)) - err = ECAP_NOREPLY; - else if (EXPECT_FALSE (obj_entry->dead)) - err = ECAP_DIED; - else - { - obj_entry->internal_refs++; - obj = obj_entry->cap_obj; - } - } - } - if (err) - { - /* Either the capability ID is invalid, or it was revoked. */ - pthread_mutex_unlock (&client->lock); - _hurd_cap_client_release (bucket, client->id); - return err; - } - - /* At this point, CAP_ID, OBJ_ENTRY and OBJ are valid. We have one - internal reference for the capability entry. */ - - /* Add ourself to the pending_rpcs list of the client. */ - _hurd_cap_list_item_add (&client->pending_rpcs, &worker_client); - pthread_mutex_unlock (&client->lock); - - cap_class = obj->cap_class; - - pthread_mutex_lock (&cap_class->lock); - /* First, we have to check if the class is inhibited, and if it is, - we have to wait until it is uninhibited. */ - while (!err && cap_class->state != _HURD_CAP_STATE_GREEN) - err = hurd_cond_wait (&cap_class->cond, &cap_class->lock); - if (err) - { - /* Canceled. */ - pthread_mutex_unlock (&cap_class->lock); - goto client_cleanup; - } - - _hurd_cap_list_item_add (&cap_class->pending_rpcs, &worker_class); - pthread_mutex_unlock (&cap_class->lock); - - - pthread_mutex_lock (&obj->lock); - /* First, we have to check if the object is inhibited, and if it is, - we have to wait until it is uninhibited. */ - if (obj->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&obj->lock); - pthread_mutex_lock (&cap_class->obj_cond_lock); - pthread_mutex_lock (&obj->lock); - while (!err && obj->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&obj->lock); - err = hurd_cond_wait (&cap_class->obj_cond, - &cap_class->obj_cond_lock); - pthread_mutex_lock (&obj->lock); - } - pthread_mutex_unlock (&cap_class->obj_cond_lock); - } - if (err) - { - /* Canceled. */ - pthread_mutex_unlock (&obj->lock); - goto class_cleanup; - } - - /* Now check if the client still has the capability, or if it was - revoked. */ - pthread_mutex_lock (&client->lock); - if (obj_entry->dead) - err = ECAP_DIED; - pthread_mutex_unlock (&client->lock); - if (err) - { - /* The capability was revoked in the meantime. */ - pthread_mutex_unlock (&obj->lock); - goto class_cleanup; - } - _hurd_cap_list_item_add (&obj->pending_rpcs, &worker_obj); - - /* At this point, we have looked up the capability, acquired an - internal reference for its entry in the client table (which - implicitely keeps a reference acquired for the object itself), - acquired a reference for the capability client in the bucket, and - have added an item to the pending_rpcs lists in the client, class - and object. The object is locked. With all this, we can finally - start to process the message for real. */ - - /* FIXME: Call the internal demuxer here, for things like reference - counter modification, cap passing etc. */ - - /* Invoke the class-specific demuxer. */ - ctx->client = client; - ctx->obj = obj; - err = (*cap_class->demuxer) (ctx); - - /* Clean up. OBJ is still locked. */ - _hurd_cap_list_item_remove (&worker_obj); - _hurd_cap_obj_cond_check (obj); - - /* Instead releasing the lock for the object, we hold it until - manage_demuxer_cleanup is called. This is important, because the - object must be locked until the reply message is sent. Consider - the impact of map items or string items. FIXME: Alternatively, - let the user set a flag if the object is locked upon return (and - must be kept lock continuously until the reply is sent). OTOH, - releasing a lock just to take it again is also pretty useless. - Needs performance measurements to make a good decision. */ - hurd_cap_obj_ref (obj); - - class_cleanup: - pthread_mutex_lock (&cap_class->lock); - _hurd_cap_list_item_remove (&worker_class); - _hurd_cap_class_cond_check (cap_class); - pthread_mutex_unlock (&cap_class->lock); - - client_cleanup: - pthread_mutex_lock (&client->lock); - _hurd_cap_list_item_remove (&worker_client); - _hurd_cap_client_cond_check (bucket, client); - - /* You are not allowed to revoke a capability while there are - pending RPCs on it. This is the reason why we know that there - must be at least one extra internal reference. FIXME: For - cleanliness, this could still call some inline function that does - the decrement. The assert can be a hint to the compiler to - optimize the inline function expansion anyway. */ - assert (!obj_entry->dead); - assert (obj_entry->internal_refs > 1); - obj_entry->internal_refs--; - pthread_mutex_unlock (&client->lock); - - _hurd_cap_client_release (bucket, client->id); - - return err; -} - - -static void -__attribute__((always_inline)) -manage_demuxer_cleanup (hurd_cap_rpc_context_t ctx) -{ - hurd_cap_obj_drop (ctx->obj); -} - - -/* A worker thread for RPC processing. The behaviour of this function - is tightly integrated with the behaviour of the manager thread. */ -static void * -manage_mt_worker (void *arg, bool async) -{ - struct worker_info *info = (struct worker_info *) arg; - hurd_cap_bucket_t bucket = info->bucket; - struct _hurd_cap_list_item worker_item; - _hurd_cap_list_item_t worker = &worker_item; - l4_thread_id_t manager = info->manager_tid; - l4_time_t timeout = info->timeout; - l4_thread_id_t from; - l4_msg_tag_t msg_tag; - bool current_worker_is_us; - - /* Prepare the worker queue item. [SYNC: As we are always the - current worker thread when we are started up, we do not add - ourselves to the free list.] */ - worker->thread = pthread_self (); - worker->tid = l4_myself (); - worker->next = NULL; - worker->prevp = NULL; - - if (EXPECT_FALSE (async)) - { - /* We have to add ourselves to the free list and inform the - worker_alloc_async thread. */ - pthread_mutex_lock (&bucket->lock); - - if (bucket->is_manager_waiting && !bucket->free_worker) - { - /* The manager is starving for worker threads. */ - pthread_cond_broadcast (&bucket->cond); - } - _hurd_cap_list_item_add (&bucket->free_worker, worker); - - /* Notify the worker_alloc_async thread that we have started up - and added ourselves to the free list. */ - bucket->worker_alloc_state = _HURD_CAP_STATE_RED; - - /* This will wake up the worker_alloc_async thread, but also the - manager in case it is blocked on getting a new worker - thread. */ - pthread_cond_broadcast (&bucket->cond); - pthread_mutex_unlock (&bucket->lock); - - /* We do not know if we will be the current worker thread or - not, so we must wait with a timeout. */ - msg_tag = l4_xreceive_timeout (manager, timeout, &from); - } - else - { - /* When we are started up, we are supposed to listen as soon as - possible to the next incoming message. When we know we are the - current worker thread, we do this without a timeout. */ - msg_tag = l4_xreceive (manager, &from); - } - - while (1) - { - if (EXPECT_FALSE (l4_ipc_failed (msg_tag))) - { - /* Slow path. */ - - l4_word_t err_code = l4_error_code (); - l4_word_t ipc_err = (err_code >> 1) & 0x7; - - if (ipc_err == L4_IPC_CANCELED || ipc_err == L4_IPC_ABORTED) - /* We have been canceled for shutdown. */ - break; - - /* The only other error that can happen is a timeout waiting - for the message. */ - assert (ipc_err == L4_IPC_TIMEOUT); - - pthread_mutex_lock (&bucket->lock); - /* If we are not on the free queue, we are the current worker. */ - current_worker_is_us = _hurd_cap_list_item_dequeued (worker); - pthread_mutex_unlock (&bucket->lock); - - /* If we are not the current worker, then we can just exit - now because of our timeout. */ - if (!current_worker_is_us) - break; - - /* If we are the current worker, we should wait here for the - next message without a timeout. */ - msg_tag = l4_xreceive (manager, &from); - /* From here, we will loop all over to the beginning of the - while(1) block. */ - } - else - { - /* Fast path. Process the RPC. */ - error_t err = 0; - struct hurd_cap_rpc_context ctx; - bool inhibited = false; - - /* IMPORTANT NOTE: The manager thread is blocked until we - reply a message with a label MSG_ACCEPTED or - MSG_REJECTED. We are supposed to return such a message - as quickly as possible. In the accepted case, we should - then process the message, while in the rejected case we - should rapidly go into the next receive. */ - - /* Before we can work on the message, we need to copy it. - This is because the MRs holding the message might be - overridden by the pthread implementation or other - function calls we make. In particular, - pthread_mutex_lock is can mangle the message buffer. */ - l4_msg_store (msg_tag, ctx.msg); - - assert (l4_ipc_propagated (msg_tag)); - assert (l4_is_thread_equal (l4_actual_sender (), manager)); - - pthread_mutex_lock (&bucket->lock); - /* We process cancellation messages regardless of the - bucket state. */ - if (EXPECT_FALSE (l4_msg_label (ctx.msg) - == HURD_CAP_MSG_LABEL_CANCEL)) - { - if (l4_untyped_words (l4_msg_msg_tag (ctx.msg)) == 1) - { - l4_thread_id_t tid = l4_msg_word (ctx.msg, 0); - - /* First verify access. Threads are only allowed to - cancel RPCs from other threads in the task. */ - if (hurd_task_id_from_thread_id (tid) - == hurd_task_id_from_thread_id (from)) - { - /* We allow cancel requests even if normal RPCs - are inhibited. */ - _hurd_cap_list_item_t pending_worker; - - pending_worker = hurd_ihash_find (&bucket->senders, - tid); - if (!pending_worker) - reply_err (from, ESRCH); - else - { - /* Found it. Cancel it. */ - pthread_cancel (pending_worker->thread); - /* Reply success. */ - reply_err (from, 0); - } - } - } - /* Set the error variable so that we return to the - manager immediately. */ - err = ECAP_NOREPLY; - } - else - { - /* Normal RPCs. */ - if (EXPECT_FALSE (bucket->state == _HURD_CAP_STATE_BLACK)) - { - /* The bucket operations have been ended, and the - manager has already been canceled. We know that - the BUCKET->senders hash is empty, so we can - quickly process the message. */ - - /* This is a normal RPC. We cancel it immediately. */ - reply_err (from, ECANCELED); - - /* Now set ERR to any error, so we return to the - manager. */ - err = ECAP_NOREPLY; /* Doesn't matter which error. */ - } - else - { - if (EXPECT_FALSE (bucket->state != _HURD_CAP_STATE_GREEN)) - { - /* If we are inhibited, we will have to wait - until we are uninhibited. */ - inhibited = true; - } - - /* FIXME: This is inefficient. ihash should support - an "add if not there" function. */ - if (EXPECT_FALSE (hurd_ihash_find (&bucket->senders, from))) - err = EBUSY; - else - { - /* FIXME: We know intimately that pthread_self is not - _HURD_IHASH_EMPTY or _HURD_IHASH_DELETED. */ - err = hurd_ihash_add (&bucket->senders, from, worker); - } - } - } - - if (EXPECT_FALSE (err)) - { - pthread_mutex_unlock (&bucket->lock); - - /* Either we already processed the message above, or - this user thread is currently in an RPC. We don't - allow asynchronous operation for security reason - (preventing DoS attacks). Silently drop the - message. */ - msg_tag = l4_niltag; - l4_set_msg_label (&msg_tag, _HURD_CAP_MSG_WORKER_REJECTED); - l4_load_mr (0, msg_tag); - - /* Reply to the manager that we don't accept the message - and wait for the next message without a timeout - (because now we know we are the current worker). */ - from = manager; - msg_tag = l4_lreply_wait (manager, &from); - - /* From here, we will loop all over to the beginning of - the while(1) block. */ - } - else - { - _hurd_cap_list_item_add (inhibited ? &bucket->waiting_rpcs - : &bucket->pending_rpcs, worker); - pthread_mutex_unlock (&bucket->lock); - - msg_tag = l4_niltag; - l4_set_msg_label (&msg_tag, _HURD_CAP_MSG_WORKER_ACCEPTED); - l4_load_mr (0, msg_tag); - msg_tag = l4_reply (manager); - assert (l4_ipc_succeeded (msg_tag)); - - /* Now we are "detached" from the manager in the sense - that we are not the current worker thread - anymore. */ - - if (EXPECT_FALSE (inhibited)) - { - pthread_mutex_lock (&bucket->lock); - while (!err && bucket->state != _HURD_CAP_STATE_GREEN - && bucket->state != _HURD_CAP_STATE_BLACK) - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - if (!err) - { - if (bucket->state == _HURD_CAP_STATE_BLACK) - err = ECANCELED; - else - { - /* State is _HURD_CAP_STATE_GREEN. Move - ourselves to the pending RPC list. */ - _hurd_cap_list_item_remove (worker); - _hurd_cap_list_item_add (&bucket->pending_rpcs, - worker); - } - } - pthread_mutex_unlock (&bucket->lock); - } - - if (EXPECT_TRUE (!err)) - { - /* Process the message. */ - ctx.sender = hurd_task_id_from_thread_id (from); - ctx.bucket = bucket; - ctx.from = from; - ctx.obj = NULL; - err = manage_demuxer (&ctx, worker); - } - - /* Post-processing. */ - - pthread_mutex_lock (&bucket->lock); - /* We have to add ourselves to the free list before (or - at the same time) as removing the client from the - pending hash, and before replying to the RPC (if we - reply in the worker thread at all). The former is - necessary to make sure that no new thread is created - in the race that would otherwise exist, namely after - replying and before adding ourself to the free list. - The latter is required because a client that - immediately follows up with a new message of course - can expect that to work properly. */ - - if (EXPECT_FALSE (bucket->is_manager_waiting - && !bucket->free_worker)) - { - /* The manager is starving for worker threads. */ - pthread_cond_broadcast (&bucket->cond); - } - - /* Remove from pending_rpcs (or waiting_rpcs) list. */ - _hurd_cap_list_item_remove (worker); - /* The last waiting RPC may have to signal the manager. */ - if (EXPECT_FALSE (inhibited - && bucket->state == _HURD_CAP_STATE_BLACK - && !bucket->waiting_rpcs)) - pthread_cond_broadcast (&bucket->cond); - _hurd_cap_list_item_add (&bucket->free_worker, worker); - - _hurd_cap_bucket_cond_check (bucket); - - /* Now that we are back on the free list it is safe to - let in the next RPC by this thread. */ - hurd_ihash_locp_remove (&bucket->senders, worker->locp); - - /* FIXME: Reap the cancellation flag here. If it was - set, we have been effectively unblocked now. From - now on, canceling us means something different than - cancelling a pending RPC (it means terminating the - worker thread). */ - - pthread_mutex_unlock (&bucket->lock); - - /* Finally, return the reply message, if appropriate. */ - if (EXPECT_TRUE (err != ECAP_NOREPLY)) - { - if (EXPECT_FALSE (err)) - reply_err (from, err); - else - { - /* We must make sure the message tag is set. */ - l4_msg_tag_t tag = l4_msg_msg_tag (ctx.msg); - l4_clear_propagation (&tag); - l4_set_msg_msg_tag (ctx.msg, tag); - l4_msg_load (ctx.msg); - l4_reply (from); - } - } - - if (ctx.obj) - manage_demuxer_cleanup (&ctx); - - /* Now listen for the next message, with a timeout. */ - from = manager; - msg_tag = l4_xreceive_timeout (manager, timeout, &from); - - /* From here, we will loop to the beginning of the - while(1) block. */ - } - } - } - - /* At this point, we have been canceled while being on the free - list, so we should go away. */ - - pthread_mutex_lock (&bucket->lock); - if (_hurd_cap_list_item_dequeued (worker)) - { - /* We are the current worker thread. We are the last worker - thread the manager thread will cancel. */ - pthread_cond_broadcast (&bucket->cond); - } - else - { - _hurd_cap_list_item_remove (worker); - if (bucket->is_manager_waiting && !bucket->free_worker) - { - /* The manager is shutting down. We are the last free - worker (except for the current worker thread) to be - canceled. */ - pthread_cond_broadcast (&bucket->cond); - } - } - pthread_mutex_unlock (&bucket->lock); - - return NULL; -} - - -/* A worker thread for RPC processing. The behaviour of this function - is tightly integrated with the behaviour of the manager thread. */ -static void * -manage_mt_worker_sync (void *arg) -{ - return manage_mt_worker (arg, false); -} - - -/* A worker thread for RPC processing. The behaviour of this function - is tightly integrated with the behaviour of the manager thread. */ -static void * -manage_mt_worker_async (void *arg) -{ - return manage_mt_worker (arg, true); -} - - -/* Return the next free worker thread. If no free worker thread is - available, create a new one. If that fails, block until one - becomes free. If we are interrupted while blocking, return - l4_nilthread. */ -static l4_thread_id_t -manage_mt_get_next_worker (struct worker_info *info, pthread_t *worker_thread) -{ - hurd_cap_bucket_t bucket = info->bucket; - l4_thread_id_t worker = l4_nilthread; - _hurd_cap_list_item_t worker_item; - - pthread_mutex_lock (&bucket->lock); - - if (EXPECT_FALSE (bucket->free_worker == NULL)) - { - /* Slow path. Create a new thread and use that. */ - error_t err; - - pthread_mutex_unlock (&bucket->lock); - worker = pthread_pool_get_np (); - if (worker == l4_nilthread) - err = EAGAIN; - else - { - err = pthread_create_from_l4_tid_np (worker_thread, NULL, - worker, manage_mt_worker_sync, - info); - /* Return the thread to the pool. */ - if (err) - pthread_pool_add_np (worker); - } - - if (!err) - { - pthread_detach (*worker_thread); - return worker; - } - else - { - pthread_mutex_lock (&bucket->lock); - if (!bucket->free_worker) - { - /* Creating a new thread failed. As a last resort, put - ourself to sleep until we are woken up by the next - free worker. Hopefully not all workers are blocking - forever. */ - - /* FIXME: To fix the case where all workers are blocking - forever, cancel one (or more? all?) (random? oldest?) - worker threads. Usually, that user will restart, but - it will nevertheless allow us to make some (although - slow) process. */ - - /* The next worker thread that adds itself to the free - list will broadcast the condition. */ - bucket->is_manager_waiting = true; - do - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - while (!err && !bucket->free_worker); - - if (err) - { - pthread_mutex_unlock (&bucket->lock); - return l4_nilthread; - } - } - } - } - - /* Fast path. A worker thread is available. Remove it from the - free list and use it. */ - worker_item = bucket->free_worker; - _hurd_cap_list_item_remove (worker_item); - pthread_mutex_unlock (&bucket->lock); - - *worker_thread = worker_item->thread; - return worker_item->tid; -} - - -/* A worker thread for allocating new worker threads. Only used if - asynchronous worker thread allocation is requested. This is only - necessary (and useful) for physmem, to break out of a potential - dead-lock with the task server. */ -static void * -worker_alloc_async (void *arg) -{ - struct worker_info *info = (struct worker_info *) arg; - hurd_cap_bucket_t bucket = info->bucket; - error_t err; - - pthread_mutex_lock (&bucket->lock); - if (bucket->state == _HURD_CAP_STATE_BLACK) - { - pthread_mutex_unlock (&bucket->lock); - return NULL; - } - - while (1) - { - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - /* We ignore the error, as the only error that can occur is - ECANCELED, and only if the bucket state has gone to black for - shutdown. */ - if (bucket->state == _HURD_CAP_STATE_BLACK) - break; - - if (bucket->worker_alloc_state == _HURD_CAP_STATE_GREEN) - { - l4_thread_id_t worker = l4_nilthread; - pthread_t worker_thread; - - pthread_mutex_unlock (&bucket->lock); - - worker = pthread_pool_get_np (); - if (worker == l4_nilthread) - err = EAGAIN; - else - { - err = pthread_create_from_l4_tid_np (&worker_thread, NULL, - worker, - manage_mt_worker_async, - info); - /* Return the thread to the pool. */ - if (err) - pthread_pool_add_np (worker); - } - - if (!err) - { - pthread_detach (worker_thread); - - pthread_mutex_lock (&bucket->lock); - bucket->worker_alloc_state = _HURD_CAP_STATE_YELLOW; - /* We ignore any error, as the only error that can occur - is ECANCELED, and only if the bucket state goes to - black for shutdown. But particularly in that case we - want to wait until the thread has fully come up and - entered the free list, so it's properly accounted for - and will be canceled at shutdown by the manager. */ - while (bucket->worker_alloc_state == _HURD_CAP_STATE_YELLOW) - err = hurd_cond_wait (&bucket->cond, &bucket->lock); - - /* Will be set by the started thread. */ - assert (bucket->worker_alloc_state == _HURD_CAP_STATE_RED); - } - else - { - pthread_mutex_lock (&bucket->lock); - bucket->worker_alloc_state = _HURD_CAP_STATE_RED; - } - - if (bucket->state == _HURD_CAP_STATE_BLACK) - break; - } - } - - bucket->worker_alloc_state = _HURD_CAP_STATE_BLACK; - pthread_mutex_unlock (&bucket->lock); - - return NULL; -} - - - -/* Start managing RPCs on the bucket BUCKET. The ROOT capability - object, which must be unlocked and have one reference throughout - the whole time this function runs, is used for bootstrapping client - connections. The GLOBAL_TIMEOUT parameter specifies the number of - seconds until the manager times out (if there are no active users). - The WORKER_TIMEOUT parameter specifies the number of seconds until - each worker thread times out (if there are no RPCs processed by the - worker thread). - - If this returns ECANCELED, then hurd_cap_bucket_end was called with - the force flag being true while there were still active users. If - this returns without any error, then the timeout expired, or - hurd_cap_bucket_end was called without active users. */ -error_t -hurd_cap_bucket_manage_mt (hurd_cap_bucket_t bucket, - hurd_cap_obj_t root, - unsigned int global_timeout_sec, - unsigned int worker_timeout_sec) -{ - error_t err; - l4_time_t global_timeout; - pthread_t worker_thread; - l4_thread_id_t worker; - struct worker_info info; - _hurd_cap_list_item_t item; - - global_timeout = (global_timeout_sec == 0) ? L4_NEVER - : l4_time_period (UINT64_C (1000000) * global_timeout_sec); - - info.bucket = bucket; - info.manager_tid = l4_myself (); - info.timeout = (worker_timeout_sec == 0) ? L4_NEVER - : l4_time_period (UINT64_C (1000000) * worker_timeout_sec); - - /* We create the first worker thread ourselves, to catch any - possible error at this stage and bail out properly if needed. */ - worker = pthread_pool_get_np (); - if (worker == l4_nilthread) - return EAGAIN; - err = pthread_create_from_l4_tid_np (&worker_thread, NULL, - worker, manage_mt_worker_sync, &info); - if (err) - { - /* Return the thread to the pool. */ - pthread_pool_add_np (worker); - return err; - } - pthread_detach (worker_thread); - - pthread_mutex_lock (&bucket->lock); - if (bucket->is_worker_alloc_async) - { - /* Prevent creation of new worker threads initially. */ - bucket->worker_alloc_state = _HURD_CAP_STATE_RED; - - /* Asynchronous worker thread allocation is requested. */ - err = pthread_create (&bucket->worker_alloc, NULL, - worker_alloc_async, &info); - - if (err) - { - /* Cancel the worker thread. */ - pthread_cancel (worker_thread); - hurd_cond_wait (&bucket->cond, &bucket->lock); - pthread_mutex_unlock (&bucket->lock); - return err; - } - } - bucket->manager = pthread_self (); - bucket->is_managed = true; - bucket->is_manager_waiting = false; - pthread_mutex_unlock (&bucket->lock); - - while (1) - { - l4_thread_id_t from = l4_anythread; - l4_msg_tag_t msg_tag; - - /* We never accept any map or grant items. FIXME: For now, we - also do not accept any string buffer items. */ - l4_accept (L4_UNTYPED_WORDS_ACCEPTOR); - - /* Because we do not accept any string items, we do not actually - need to set the Xfer timeouts. But this is what we want to set - them to when we eventually do support string items. */ - l4_set_xfer_timeouts (l4_timeouts (L4_ZERO_TIME, L4_ZERO_TIME)); - - /* FIXME: Make sure we have enabled deferred cancellation, and - use an L4 ipc() stub that supports that. In fact, this must - be true for most of the IPC operations in this file. */ - msg_tag = l4_wait_timeout (global_timeout, &from); - - if (EXPECT_FALSE (l4_ipc_failed (msg_tag))) - { - l4_word_t err_code = l4_error_code (); - - /* FIXME: We need a macro or inline function for that. */ - l4_word_t ipc_err = (err_code >> 1) & 0x7; - - /* There are two possible errors, cancellation or timeout. - Any other error indicates a bug in the code. */ - if (ipc_err == L4_IPC_CANCELED || ipc_err == L4_IPC_ABORTED) - { - /* If we are canceled, then this means that our state is - now _HURD_CAP_STATE_BLACK and we should end managing - RPCs even if there are still active users. */ - - pthread_mutex_lock (&bucket->lock); - assert (bucket->state == _HURD_CAP_STATE_BLACK); - err = ECANCELED; - break; - } - else - { - assert (((err_code >> 1) & 0x7) == L4_IPC_TIMEOUT); - - pthread_mutex_lock (&bucket->lock); - /* Check if we can time out safely. */ - if (bucket->state == _HURD_CAP_STATE_GREEN - && !bucket->nr_caps && !bucket->pending_rpcs - && !bucket->waiting_rpcs) - { - err = 0; - break; - } - pthread_mutex_unlock (&bucket->lock); - } - } - else - { - /* Propagate the message to the worker thread. */ - l4_set_propagation (&msg_tag); - l4_set_virtual_sender (from); - l4_set_msg_tag (msg_tag); - - /* FIXME: Make sure to use a non-cancellable l4_lcall that - does preserve any pending cancellation flag for this - thread. Alternatively, we can handle cancellation here - (reply ECANCELED to user, and enter shutdown - sequence. */ - msg_tag = l4_lcall (worker); - assert (l4_ipc_succeeded (msg_tag)); - - if (EXPECT_TRUE (l4_label (msg_tag) - == _HURD_CAP_MSG_WORKER_ACCEPTED)) - { - worker = manage_mt_get_next_worker (&info, &worker_thread); - if (worker == l4_nilthread) - { - /* The manage_mt_get_next_worker thread was - canceled. In this case we have to terminate - ourselves. */ - err = hurd_cap_bucket_inhibit (bucket); - assert (!err); - hurd_cap_bucket_end (bucket, true); - - pthread_mutex_lock (&bucket->lock); - err = ECANCELED; - break; - } - } - } - } - - /* At this point, bucket->lock is held. Start the shutdown - sequence. */ - assert (!bucket->pending_rpcs); - - /* First shutdown the allocator thread, if any. */ - if (bucket->is_worker_alloc_async) - { - pthread_cancel (bucket->worker_alloc); - pthread_join (bucket->worker_alloc, NULL); - } - - /* Now force all the waiting rpcs onto the free list. They will - have noticed the state change to _HURD_CAP_STATE_BLACK already, - we just have to block until the last one wakes us up. */ - while (bucket->waiting_rpcs) - hurd_cond_wait (&bucket->cond, &bucket->lock); - - /* Cancel the free workers. */ - item = bucket->free_worker; - while (item) - { - pthread_cancel (item->thread); - item = item->next; - } - - /* Request the condition to be broadcasted. */ - bucket->is_manager_waiting = true; - - while (bucket->free_worker) - { - /* We ignore cancellations at this point, because we are already - shutting down. */ - hurd_cond_wait (&bucket->cond, &bucket->lock); - } - - /* Now cancel the current worker, except if we were canceled while - trying to get a new one (in which case there is no current - worker). */ - if (worker != l4_nilthread) - { - pthread_cancel (worker_thread); - hurd_cond_wait (&bucket->cond, &bucket->lock); - } - - bucket->is_managed = false; - pthread_mutex_unlock (&bucket->lock); - - return err; -} diff --git a/libhurd-cap-server/bucket-worker-alloc.c b/libhurd-cap-server/bucket-worker-alloc.c deleted file mode 100644 index be1167d..0000000 --- a/libhurd-cap-server/bucket-worker-alloc.c +++ /dev/null @@ -1,51 +0,0 @@ -/* bucket-worker-alloc.c - Set the worker allocation policy. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include "cap-server-intern.h" - - -/* If ASYNC is true, allocate worker threads asynchronously whenever - the number of worker threads is exhausted. This is only actually - required for physmem (the physical memory server), to allow to - break out of a dead-lock between physmem and the task server. It - should be unnecessary for any other server. - - The default is to false, which means that worker threads are - allocated synchronously by the manager thread. - - This function should be called before the manager is started with - hurd_cap_bucket_manage_mt. It is only used for the multi-threaded - RPC manager. */ -error_t -hurd_cap_bucket_worker_alloc (hurd_cap_bucket_t bucket, bool async) -{ - pthread_mutex_lock (&bucket->lock); - bucket->is_worker_alloc_async = async; - pthread_mutex_unlock (&bucket->lock); - - return 0; -} diff --git a/libhurd-cap-server/cap-server-intern.h b/libhurd-cap-server/cap-server-intern.h deleted file mode 100644 index 8d87116..0000000 --- a/libhurd-cap-server/cap-server-intern.h +++ /dev/null @@ -1,599 +0,0 @@ -/* cap-server-intern.h - Internal interface to the Hurd capability library. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _HURD_CAP_SERVER_INTERN_H -#define _HURD_CAP_SERVER_INTERN_H 1 - -#include <hurd/types.h> -#include <hurd/ihash.h> -#include <hurd/cap-server.h> - -#include <compiler.h> - -#include "table.h" -#include "task-death.h" - - -/* FIXME: For now. */ -#define hurd_cond_wait pthread_cond_wait - -/* Every capability hurd_cap_handle_t consists of two parts: The upper - part is a client ID and the lower part is a capability object ID. - The client ID is as long as the task ID (which is as long as the - version ID). The cap ID occupies the remainder. We intimately - know that even on 64 bit architectures, both fit into a 32 bit - integer value. */ -#define _HURD_CAP_CLIENT_ID_BITS HURD_TASK_ID_BITS -#define _HURD_CAP_ID_BITS ((sizeof (hurd_cap_handle_t) * 8) \ - - HURD_TASK_ID_BITS) - -#define _HURD_CAP_CLIENT_ID_MASK \ - ((L4_WORD_C(1) << _HURD_CAP_CLIENT_ID_BITS) - 1) -#define _HURD_CAP_ID_MASK ((L4_WORD_C(1) << _HURD_CAP_ID_BITS) - 1) - -typedef l4_uint32_t _hurd_cap_id_t; -typedef l4_uint32_t _hurd_cap_client_id_t; - - -/* Get the capability ID from a user capability. The capabililty ID - is an index into the caps table of a client. */ -static inline _hurd_cap_client_id_t -__attribute__((always_inline)) -_hurd_cap_client_id (hurd_cap_handle_t cap) -{ - return cap >> _HURD_CAP_ID_BITS; -} - - -/* Get the capability ID from a user capability. The capabililty ID - is an index into the caps table of a client. */ -static inline _hurd_cap_id_t -__attribute__((always_inline)) -_hurd_cap_id (hurd_cap_handle_t cap) -{ - return cap & _HURD_CAP_ID_MASK; -} - - -/* Create a new capability handle from the client and cap ID. */ -static inline hurd_cap_handle_t -__attribute__((always_inline)) -_hurd_cap_handle_make (_hurd_cap_client_id_t client_id, _hurd_cap_id_t cap_id) -{ - return ((client_id & _HURD_CAP_CLIENT_ID_MASK) << _HURD_CAP_ID_BITS) - | (cap_id & _HURD_CAP_ID_MASK); -} - - -/* This is a simple list item, used to maintain lists of pending RPC - worker threads in a class, client or capability object. */ -struct _hurd_cap_list_item -{ - _hurd_cap_list_item_t next; - _hurd_cap_list_item_t *prevp; - - union - { - /* Used for maintaining lists of pending RPC worker threads in a - class, client or capability object. */ - struct - { - /* This location pointer is used for fast removal from the - BUCKET->senders. */ - hurd_ihash_locp_t locp; - - /* The worker thread processing the RPC. */ - pthread_t thread; - - /* The worker thread L4 thread ID. */ - l4_thread_id_t tid; - }; - - /* Used for reverse lookup of capability clients using a - capability object. */ - struct - { - _hurd_cap_client_t client; - }; - }; -}; - -/* Add the list item ITEM to the list LIST. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_list_item_add (_hurd_cap_list_item_t *list, - _hurd_cap_list_item_t item) -{ - if (*list) - (*list)->prevp = &item->next; - item->prevp = list; - item->next = *list; - *list = item; -} - - -/* Remove the list item ITEM from the list. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_list_item_remove (_hurd_cap_list_item_t item) -{ - if (item->next) - item->next->prevp = item->prevp; - *(item->prevp) = item->next; - item->prevp = NULL; -} - - -/* Check if the item ITEM is dequeued or not. */ -static inline bool -__attribute__((always_inline)) -_hurd_cap_list_item_dequeued (_hurd_cap_list_item_t item) -{ - return item->prevp == NULL; -} - - -/* Deallocate the capability object OBJ, which must be locked and have - no more references. */ -void _hurd_cap_obj_dealloc (hurd_cap_obj_t obj) - __attribute__((visibility("hidden"))); - - -/* Remove one reference for the capability object OBJ, which must be - locked, and will be unlocked when the function returns. If this - was the last user of this object, the object is deallocated. */ -static inline void -_hurd_cap_obj_drop (hurd_cap_obj_t obj) -{ - if (EXPECT_TRUE (!atomic_decrement_and_test (&obj->refs))) - hurd_cap_obj_unlock (obj); - else - _hurd_cap_obj_dealloc (obj); -} - - -/* Client capabilities. */ - -/* The following data type is used pointed to by an entry in the caps - table of a client. Except noted otherwise, its members are - protected by the same lock as the table. */ -struct _hurd_cap_obj_entry -{ - /* The capability object. */ - hurd_cap_obj_t cap_obj; - - /* The index in the capability table. */ - _hurd_cap_id_t id; - - /* A list item that is used for reverse lookup from the capability - object to the client. Protected by the lock of the capability - object. */ - struct _hurd_cap_list_item client_item; - - /* A flag that indicates if this capability is dead (revoked). Note - that CAP_OBJ is still valid until all internal references have - been removed. */ - unsigned int dead : 1; - - /* The number of internal references. These are references taken by - the server for its own purpose. In fact, there is one such - reference for all outstanding external references (if the dead - flag is not set), and one for each pending RPC that uses this - capability. If this reference counter drops to zero, the one - real capability object reference held by this capability entry is - released, and CAP_OBJ becomes invalid. */ - unsigned int internal_refs : 15; - - /* The number of external references. These are references granted - to the user. For all these references, one internal reference is - taken, unless the DEAD flag is set. */ - unsigned int external_refs : 16; -}; -typedef struct _hurd_cap_obj_entry *_hurd_cap_obj_entry_t; - - -/* The global slab for all capability entries. */ -extern struct hurd_slab_space _hurd_cap_obj_entry_space - __attribute__((visibility("hidden"))); - -/* Copy out a capability for the capability OBJ to the user CLIENT. - Returns the capability ID (valid only for this user) in *R_ID, or - an error. OBJ must be locked. */ -error_t _hurd_cap_obj_copy_out (hurd_cap_obj_t obj, hurd_cap_bucket_t bucket, - _hurd_cap_client_t client, _hurd_cap_id_t *r_id) - __attribute__((visibility("hidden"))); - - -/* Client connections. */ - - -/* Instances of the following data type are pointed to by the client - table of a bucket. Its members are protected by the same lock as - the table. The data type holds all the information about a client - connection. */ -struct _hurd_cap_client -{ - /* A flag that indicates if this capability client is dead. This - data structure is valid until all references have been removed, - though. Note that because there is one reference for the task - info capability, this means that CLIENT is valid until a task - death notification has been processed for this client. Protected - by the containing bucket's lock LOCK. */ - unsigned int dead : 1; - - /* Reference counter. A reference is held if the client is live - (and removed by the task death handler). One reference is held - by each pending RPC. Temporarily, additional references may be - held by RPCs that have just started, but they will rip themselves - when they see the DEAD flag. Protected by the containing - bucket's lock LOCK. */ - unsigned int refs : 31; - - /* The task ID of the client. */ - hurd_task_id_t task_id; - - /* The index of the client in the client table of the bucket. - This is here so that we can hash for the address of this struct - in the clients_reverse hash of the bucket, and still get the - index number. This allows us to use a location pointer for - removal (locp) for fast hash removal. */ - _hurd_cap_client_id_t id; - - /* The location pointer for fast removal from the reverse lookup - hash BUCKET->clients_reverse. This is protected by the bucket - lock. */ - hurd_ihash_locp_t locp; - - /* The lock protecting all the following members. Client locks can - be taken while capability object locks are held! This is very - important when copying or removing capabilities. On the other - hand, this means you are not allowed to lock cabaility objects - when holding a client lock. */ - pthread_mutex_t lock; - - /* The state of the client. If this is _HURD_CAP_STATE_GREEN, you - can process RPCs for this client. Otherwise, you should drop - RPCs for this client. If this is _HURD_CAP_STATE_YELLOW, and you - are the last pending_rpc to finish, you have to broadcast the - client_cond of the bucket. */ - enum _hurd_cap_state state; - - /* The current waiter thread. This is only valid if state is - _HURD_CAP_STATE_YELLOW. Used by _hurd_cap_client_cond_busy (). */ - pthread_t cond_waiter; - - /* The pending RPC list. Each RPC worker thread should add itself - to this list, so it can be cancelled by the task death - notification handler. */ - struct _hurd_cap_list_item *pending_rpcs; - - /* The _hurd_cap_id_t to _hurd_cap_obj_entry_t mapping. */ - struct hurd_table caps; - - /* Reverse lookup from hurd_cap_obj_t to _hurd_cap_obj_entry_t. */ - struct hurd_ihash caps_reverse; -}; - - -/* The global slab space for all capability clients. */ -extern struct hurd_slab_space _hurd_cap_client_space - __attribute__((visibility("hidden"))); - - -/* Look up the client with the task ID TASK in the class CLASS, and - return it in R_CLIENT, with one additional reference. If it is not - found, create it. */ -error_t _hurd_cap_client_create (hurd_cap_bucket_t bucket, - hurd_task_id_t task_id, - _hurd_cap_client_t *r_client) - __attribute__((visibility("hidden"))); - - -/* Deallocate the connection client CLIENT. */ -void _hurd_cap_client_dealloc (hurd_cap_bucket_t bucket, - _hurd_cap_client_t client) - __attribute__((visibility("hidden"))); - - -/* Release a reference for the client with the ID IDX in class - CLASS. */ -void _hurd_cap_client_release (hurd_cap_bucket_t bucket, - _hurd_cap_client_id_t idx) - __attribute__((visibility("hidden"))); - - -/* Inhibit all RPCs on the capability client CLIENT (which must not be - locked) in the bucket BUCKET. You _must_ follow up with a - hurd_cap_client_resume operation, and hold at least one reference - to the object continuously until you did so. */ -error_t _hurd_cap_client_inhibit (hurd_cap_bucket_t bucket, - _hurd_cap_client_t client) - __attribute__((visibility("hidden"))); - - -/* Resume RPCs on the capability client CLIENT in the bucket BUCKET - and wake-up all waiters. */ -void _hurd_cap_client_resume (hurd_cap_bucket_t bucket, - _hurd_cap_client_t client) - __attribute__((visibility("hidden"))); - - -/* End RPCs on the capability client CLIENT in the bucket BUCKET and - wake-up all waiters. */ -void _hurd_cap_client_end (hurd_cap_bucket_t bucket, - _hurd_cap_client_t client) - __attribute__((visibility("hidden"))); - - -/* Buckets are a set of capabilities, on which RPCs are managed - collectively. */ - -struct _hurd_cap_bucket -{ - /* Client management. */ - - /* The following condition is used in conjunction with the state - predicate of the client associated with the the currently - processed death task notification. */ - pthread_cond_t client_cond; - - /* The following mutex is associated with the client_cond condition. - Note that this mutex does _not_ protect the predicate of the - condition: The predicate is the state of the respective client - and that is protected by the lock of each client itself. In - fact, this mutex has no purpose but to serve the condition. The - reason is that this way we avoid lock contention when checking - the state of a client. - - So, first you lock the client structure. You have to do this - anyway. Then you check the state. If the state is - _HURD_CAP_STATE_GREEN, you can unlock the client and continue - normally. However, if the state is _HURD_CAP_STATE_YELLOW, you - have to unlock the client, lock this mutex, then lock the client - again and reinvestigate the state. If necessary (ie, you are the - last RPC except the waiter) you can set the state to - _HURD_CAP_STATE_RED and broadcast the condition. This sounds - cumbersome, but the important part is that the common case, the - _HURD_CAP_STATE_GREEN, is handled quickly and without class-wide - lock contention. */ - pthread_mutex_t client_cond_lock; - - /* The following entry is protected by hurd_task_death_notify_lock. */ - struct hurd_task_death_notify_list_item client_death_notify; - - - /* Bucket management. */ - - /* The following members are protected by this lock. */ - pthread_mutex_t lock; - - /* The manager thread for this capability class. */ - pthread_t manager; - - /* True if MANAGER is valid and the bucket is managed. */ - bool is_managed; - - /* If this is true, then the manager is waiting for the free worker - list to become empty (at shutdown) or filled (else). The first - worker thread to notice that the condition is fulfilled now - should broadcast the condition. */ - bool is_manager_waiting; - - /* The state of the bucket. */ - _hurd_cap_state_t state; - - /* The condition used to wait on state changes and changes in the - worker thread list. */ - pthread_cond_t cond; - - /* The thread waiting for the RPCs to be inhibited. */ - pthread_t cond_waiter; - - /* The number of capabilities. If this is not 0, then there are - active users. */ - unsigned int nr_caps; - - /* The pending RPCs in this bucket. */ - _hurd_cap_list_item_t pending_rpcs; - - /* The waiting RPCs in this bucket. */ - _hurd_cap_list_item_t waiting_rpcs; - - /* The free worker threads in this bucket. */ - _hurd_cap_list_item_t free_worker; - - /* A hash from l4_thread_id_t to _hurd_cap_list_item_t (the list - items in PENDING_RPCs). This is used to limit each client thread - to just one RPC at one time. */ - struct hurd_ihash senders; - - /* Mapping from hurd_cap_client_id_t to _hurd_cap_client_t. */ - struct hurd_table clients; - - /* Reverse lookup from hurd_task_id_t to _hurd_cap_client_t. */ - struct hurd_ihash clients_reverse; - - /* This is true if worker threads should be allocated - asynchronously. */ - bool is_worker_alloc_async; - - /* If WORKER_ALLOC_ASYNC is true, this is the state of the worker - thread allocation thread. If this is _HURD_CAP_STATE_GREEN, then - a new thread should be allocated. If this is - _HURD_CAP_STATE_YELLOW, the worker thread has allocated a new - thread, and is currently waiting for the thread to complete its - startup. If this is _HURD_CAP_STATE_RED, the new worker thread - has completed its startup (if one was started) and no new thread - will be allocated. */ - _hurd_cap_state_t worker_alloc_state; - - /* If WORKER_ALLOC_ASYNC is true, this is the allocator thread. */ - pthread_t worker_alloc; -}; - - -/* Return true if there are still outstanding RPCs in this bucket - BUCKET, and fails if not. This is only valid if - hurd_cap_bucket_inhibit is in progress (ie, if bucket->state is - _HURD_CAP_STATE_YELLOW). BUCKET must be locked. */ -static inline int -__attribute__((always_inline)) -_hurd_cap_bucket_cond_busy (hurd_cap_bucket_t bucket) -{ - /* We have to remain in the state yellow until there are no pending - RPC threads except maybe the waiter. */ - return bucket->pending_rpcs - && (bucket->pending_rpcs->thread != bucket->cond_waiter - || bucket->pending_rpcs->next); -} - - -/* Check if the inhibition state of the capability bucket BUCKET has - to be changed. BUCKET must be locked. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_bucket_cond_check (hurd_cap_bucket_t bucket) -{ - if (bucket->state == _HURD_CAP_STATE_YELLOW - && !_hurd_cap_bucket_cond_busy (bucket)) - { - bucket->state =_HURD_CAP_STATE_RED; - pthread_cond_broadcast (&bucket->cond); - } -} - - -/* Capability clients. */ - -/* Return true if there are still outstanding RPCs in this capability - client, and fails if not. CLIENT must be locked. This is only - valid if hurd_cap_client_inhibit is in progress (ie, if - client->state is _HURD_CAP_STATE_YELLOW). */ -static inline int -__attribute__((always_inline)) -_hurd_cap_client_cond_busy (_hurd_cap_client_t client) -{ - /* We have to remain in the state yellow until there are no pending - RPC threads except maybe the waiter. */ - return client->pending_rpcs - && (client->pending_rpcs->thread != client->cond_waiter - || client->pending_rpcs->next); -} - - -/* Check if the inhibited state of the capability client CLIENT has to - be changed. CLIENT must be locked. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_client_cond_check (hurd_cap_bucket_t bucket, - _hurd_cap_client_t client) -{ - if (client->state == _HURD_CAP_STATE_YELLOW - && !_hurd_cap_client_cond_busy (client)) - { - client->state = _HURD_CAP_STATE_RED; - pthread_cond_broadcast (&bucket->client_cond); - } -} - - -/* Capability classes. */ - -/* Return true if there are still outstanding RPCs in this class, and - fails if not. CAP_CLASS must be locked. This is only valid if - hurd_cap_class_inhibit is in progress (ie, if cap_class->state is - _HURD_CAP_STATE_YELLOW). */ -static inline int -__attribute__((always_inline)) -_hurd_cap_class_cond_busy (hurd_cap_class_t cap_class) -{ - /* We have to remain in the state yellow until there are no pending - RPC threads except maybe the waiter. */ - return cap_class->pending_rpcs - && (cap_class->pending_rpcs->thread != cap_class->cond_waiter - || cap_class->pending_rpcs->next); -} - - -/* Check if the inhibition state of the capability class CAP_CLASS has - to be changed. CAP_CLASS must be locked. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_class_cond_check (hurd_cap_class_t cap_class) -{ - if (cap_class->state == _HURD_CAP_STATE_YELLOW - && !_hurd_cap_class_cond_busy (cap_class)) - { - cap_class->state = _HURD_CAP_STATE_RED; - pthread_cond_broadcast (&cap_class->cond); - } -} - - -/* Capability objects. */ - -/* Return true if there are still outstanding RPCs in this capability - object, and fails if not. OBJ must be locked. This is only valid - if hurd_cap_obj_inhibit is in progress (ie, if cap_obj->state is - _HURD_CAP_STATE_YELLOW). */ -static inline int -__attribute__((always_inline)) -_hurd_cap_obj_cond_busy (hurd_cap_obj_t obj) -{ - /* We have to remain in the state yellow until there are no pending - RPC threads except maybe the waiter. */ - return obj->pending_rpcs - && (obj->pending_rpcs->thread != obj->cond_waiter - || obj->pending_rpcs->next); -} - - -/* Check if the inhibition state of the capability class CAP_CLASS has - to be changed. CAP_CLASS must be locked. */ -static inline void -__attribute__((always_inline)) -_hurd_cap_obj_cond_check (hurd_cap_obj_t obj) -{ - if (obj->state == _HURD_CAP_STATE_YELLOW - && !_hurd_cap_obj_cond_busy (obj)) - { - obj->state = _HURD_CAP_STATE_RED; - pthread_cond_broadcast (&obj->cap_class->cond); - } -} - -/* The following structure is used when using other capabilities in an - RPC handler beside the one on which the RPC was invoked. */ -struct hurd_cap_ctx_cap_use -{ - /* Private members. */ - - _hurd_cap_obj_entry_t _obj_entry; - - /* The pending_rpc list item for the object's pending RPC list. */ - struct _hurd_cap_list_item _worker_obj; - - /* The pending_rpc list item for the object class' pending RPC list. */ - struct _hurd_cap_list_item _worker_class; -}; - - -#endif /* _HURD_CAP_SERVER_INTERN_H */ diff --git a/libhurd-cap-server/cap-server.h b/libhurd-cap-server/cap-server.h deleted file mode 100644 index e12e986..0000000 --- a/libhurd-cap-server/cap-server.h +++ /dev/null @@ -1,573 +0,0 @@ -/* cap-server.h - Server interface to the Hurd capability library. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _HURD_CAP_SERVER_H -#define _HURD_CAP_SERVER_H 1 - -#include <stdbool.h> -#include <errno.h> -#include <pthread.h> - -/* FIXME: This is not a public header file! So we may have to ship - a <hurd/atomic.h>. */ -#include <atomic.h> - -#include <hurd/slab.h> -#include <hurd/types.h> - - -/* Internal declarations. */ - -/* This is a simple list item, used to maintain lists of pending RPC - worker threads in a capability class, client, or object. */ -struct _hurd_cap_list_item; -typedef struct _hurd_cap_list_item *_hurd_cap_list_item_t; - - -/* The state of a capability class, client, or object. */ -typedef enum _hurd_cap_state - { - _HURD_CAP_STATE_GREEN, - _HURD_CAP_STATE_YELLOW, - _HURD_CAP_STATE_RED, - _HURD_CAP_STATE_BLACK - } -_hurd_cap_state_t; - - -/* Public interface. */ - -/* Forward declarations. */ -struct _hurd_cap_bucket; -typedef struct _hurd_cap_bucket *hurd_cap_bucket_t; -struct _hurd_cap_client; -typedef struct _hurd_cap_client *_hurd_cap_client_t; -struct hurd_cap_class; -typedef struct hurd_cap_class *hurd_cap_class_t; -struct hurd_cap_obj; -typedef struct hurd_cap_obj *hurd_cap_obj_t; - - -typedef error_t (*hurd_cap_obj_init_t) (hurd_cap_class_t cap_class, - hurd_cap_obj_t obj); -typedef error_t (*hurd_cap_obj_alloc_t) (hurd_cap_class_t cap_class, - hurd_cap_obj_t obj); -typedef void (*hurd_cap_obj_reinit_t) (hurd_cap_class_t cap_class, - hurd_cap_obj_t obj); -typedef void (*hurd_cap_obj_destroy_t) (hurd_cap_class_t cap_class, - hurd_cap_obj_t obj); - - -/* The RPC context contains various information for the RPC handler - and the support functions. */ -struct hurd_cap_rpc_context -{ - /* Public members. */ - - /* The task which contained the sender of the message. */ - hurd_task_id_t sender; - - /* The bucket through which the message was received. */ - hurd_cap_bucket_t bucket; - - /* The capability object on which the RPC was invoked. */ - hurd_cap_obj_t obj; - - /* The capability handle on which the RPC was invoked. */ - hurd_cap_handle_t handle; - - /* Private members. */ - - /* The sender of the message. */ - l4_thread_id_t from; - - /* The client corresponding to FROM. */ - _hurd_cap_client_t client; - - /* The message. */ - l4_msg_t msg; -}; -typedef struct hurd_cap_rpc_context *hurd_cap_rpc_context_t; - -/* FIXME: Add documentation. */ -typedef error_t (*hurd_cap_class_demuxer_t) (hurd_cap_rpc_context_t ctx); - - -/* A capability class is a group of capability objects of the same - type. */ -struct hurd_cap_class -{ - /* Capability object management for the class. */ - - /* The following callbacks are used to adjust the state of an object - during its lifetime: - - 1. Object is constructed in the cache OBJ_INIT - 2.1. Object is instantiated and removed from the free list OBJ_ALLOC - 2.2. Object is deallocated and put back on the free list OBJ_REINIT - 3. Object is destroyed and removed from the cache OBJ_DESTROY - - Note that step 2 can occur several times, or not at all. - This is the state diagram for each object: - - (START) --(1.)-> initialized --(3.)--> destroyed (END) - | ^ - | | - (2.1.) (2.2.) - | | - v | - allocated - - Note that OBJ_INIT will be called in bursts for pre-allocation of - several objects. */ - - /* This callback is invoked whenever a new object is pre-allocated - in the cache. It is usually called in bursts when a new slab - page is allocated. You can put all initialization in it that - should be cached. */ - hurd_cap_obj_init_t obj_init; - - /* This callback is called whenever an object in the cache is going - to be instantiated and used. You can put further initialization - in it that is not suitable for caching (for example, because it - can not be safely reinitialized by OBJ_REINIT). If OBJ_ALLOC - fails, then it must leave the object in its initialized - state! */ - hurd_cap_obj_alloc_t obj_alloc; - - /* This callback is invoked whenever a used object is deallocated - and returned to the cache. It should revert the used object to - its initialized state, this means as if OBJ_INIT had been called - on a freshly constructed object. This also means that you have - to deallocate all resources that have been allocated by - OBJ_ALLOC. Note that this function can not fail. Initialization - that can not be safely (error-free) reverted to its original - state must be put into the OBJ_ALLOC callback, rather than in the - OBJ_INIT callback. */ - hurd_cap_obj_reinit_t obj_reinit; - - /* This callback is invoked whenever an initialized, but unused - object is removed from the cache and destroyed. You should - release all resources that have been allocated for this object by - a previous OBJ_INIT invocation. */ - hurd_cap_obj_destroy_t obj_destroy; - - /* The slab space containing the capabilities in this class. */ - struct hurd_slab_space obj_space; - - /* The following condition is used in conjunction with the state - predicate of a capability object. */ - pthread_cond_t obj_cond; - - /* The following mutex is associated with the obj_cond - condition. Note that this mutex does _not_ protect the predicate - of the condition: The predicate is the state of the respective - client and that is protected by the lock of each capability - object itself. */ - pthread_mutex_t obj_cond_lock; - - - /* The class management. */ - - /* The demuxer for this class. */ - hurd_cap_class_demuxer_t demuxer; - - /* The lock protecting all the following members. */ - pthread_mutex_t lock; - - /* The state of the class. */ - _hurd_cap_state_t state; - - /* The condition used for waiting on state changes. The associated - mutex is LOCK. */ - pthread_cond_t cond; - - /* The current waiter thread. This is only valid if state is - _HURD_CAP_STATE_YELLOW. Used by _hurd_cap_class_cond_busy (). */ - pthread_t cond_waiter; - - /* The pending RPC worker threads for this class. */ - _hurd_cap_list_item_t pending_rpcs; -}; - - -/* Server-side objects that are accessible via capabilities. */ -struct hurd_cap_obj -{ - /* The class which contains this capability. */ - hurd_cap_class_t cap_class; - - /* The lock protecting all the members of the capability object. */ - pthread_mutex_t lock; - - /* The reference counter for this object. */ - uatomic32_t refs; - - /* The state of the capability object. - - If STATE is _HURD_CAP_STATE_GREEN, you can use the capability - object. Otherwise, you must wait on the condition - CAP_CLASS->OBJ_COND for it return to _HURD_CAP_STATE_GREEN. - - If the state is _HURD_CAP_STATE_YELLOW, a thread wants the state - to be _HURD_CAP_STATE_RED (and it has canceled all other pending - RPC threads on this object). The last worker thread for this - capability object (other than the thread waiting for the - condition to become _HURD_CAP_STATE_RED) must broadcast the - obj_state_cond condition. - - Every worker thread that blocks on the capability object state - until it reverts to _HURD_CAP_STATE_GREEN must perform a - reauthentication when it is unblocked (ie, verify that the client - still has access to the capability object), in case the - capability of the client for this object was revoked in the - meantime. - - _HURD_CAP_STATE_BLACK is not used for capability objects. */ - _hurd_cap_state_t state; - - /* The pending RPC worker threads for this capability object. */ - _hurd_cap_list_item_t pending_rpcs; - - /* The current waiter thread. This is only valid if STATE is - _HURD_CAP_STATE_YELLOW. Used by _hurd_cap_obj_cond_busy (). */ - pthread_t cond_waiter; - - /* The list items in the capability entries of the clients using - this capability. */ - _hurd_cap_list_item_t clients; -}; - - -/* Operations on capability classes. */ - -/* Create a new capability class for objects with the size SIZE and - alignment requirement ALIGNMENT (which must be a power of 2). - - The callback OBJ_INIT is used whenever a capability object in this - class is created. The callback OBJ_REINIT is used whenever a - capability object in this class is deallocated and returned to the - slab. OBJ_REINIT should bring back a capability object that is not - used anymore into the same state as OBJ_INIT does for a freshly - allocated object. OBJ_DESTROY should deallocate all resources for - this capablity object. Note that OBJ_REINIT can not fail: If you - have resources that can not safely be restored into their initial - state, you cannot use OBJ_INIT to allocate them. Furthermore, note - that OBJ_INIT will usually be called in bursts for advanced - allocation. - - The new capability class is returned in R_CLASS. If the creation - fails, an error value will be returned. */ -error_t hurd_cap_class_create_untyped (size_t size, size_t alignment, - hurd_cap_obj_init_t obj_init, - hurd_cap_obj_alloc_t obj_alloc, - hurd_cap_obj_reinit_t obj_reinit, - hurd_cap_obj_destroy_t obj_destroy, - hurd_cap_class_demuxer_t demuxer, - hurd_cap_class_t *r_class); - -/* Define a capability class for the pointer type TYPE. */ -#define hurd_cap_class_create(type,init,alloc,reinit,destroy,demuxer,r_class) \ - hurd_cap_class_create_untyped (({ type t; sizeof (*t); }), \ - ({ type t; __alignof__ (*t); }), \ - init, alloc, reinit, destroy, demuxer, \ - r_class); - - -/* Destroy the capability class CAP_CLASS and release all associated - resources. Note that this is only allowed if there are no - capability objects in use, and if the capability class is not used - by a capability server. This function assumes that the class was - created with hurd_cap_class_create. */ -error_t hurd_cap_class_free (hurd_cap_class_t cap_class); - - -/* Same as hurd_cap_class_create, but doesn't allocate the storage for - CAP_CLASS. Instead, you have to provide it. */ -error_t hurd_cap_class_init_untyped (hurd_cap_class_t cap_class, - size_t size, size_t alignment, - hurd_cap_obj_init_t obj_init, - hurd_cap_obj_alloc_t obj_alloc, - hurd_cap_obj_reinit_t obj_reinit, - hurd_cap_obj_destroy_t obj_destroy, - hurd_cap_class_demuxer_t demuxer); - -/* Define a capability class for the pointer type TYPE. */ -#define hurd_cap_class_init(cclass,type,init,alloc,reinit,destroy,demuxer) \ - hurd_cap_class_init_untyped (cclass, ({ type t; sizeof (*t); }), \ - ({ type t; __alignof__ (*t); }), \ - init, alloc, reinit, destroy, demuxer); - - -/* Destroy the capability class CAP_CLASS and release all associated - resources. Note that this is only allowed if there are no - capability objects in use, and if the capability class is not used - by a capability server. This function assumes that the class has - been initialized with hurd_cap_class_init. */ -error_t hurd_cap_class_destroy (hurd_cap_class_t cap_class); - - -/* Allocate a new capability object in the class CAP_CLASS. The new - capability object is locked and has one reference. It will be - returned in R_OBJ. If the allocation fails, an error value will be - returned. The object will be destroyed as soon as its last - reference is dropped. */ -error_t hurd_cap_class_alloc (hurd_cap_class_t cap_class, - hurd_cap_obj_t *r_obj); - - -/* Get the offset of the user object following a capability. - ALIGNMENT is the alignment requirements of the user object as - supplied to hurd_cap_class_init, hurd_cap_class_init_untyped, - hurd_cap_class_create or hurd_cap_class_create_untyped. */ -static inline size_t -__attribute__((__always_inline__)) -hurd_cap_obj_user_offset (size_t alignment) -{ - size_t offset = sizeof (struct hurd_cap_obj); - size_t rest = sizeof (struct hurd_cap_obj) % alignment; - - if (rest) - offset += alignment - rest; - - return offset; -} - - -/* Find the user object of the pointer type TYPE after the capability - object OBJ. Note that in conjunction with the hurd_cap_obj_to_user - macro below, all of this can and will be computed at compile time, - if optimization is enabled. OBJ already fulfills the alignment - requirement ALIGNMENT. */ -static inline void * -__attribute__((__always_inline__)) -hurd_cap_obj_to_user_untyped (hurd_cap_obj_t obj, size_t alignment) -{ - uintptr_t obj_addr = (uintptr_t) obj; - - obj_addr += hurd_cap_obj_user_offset (alignment); - - return (void *) obj_addr; -} - -#define hurd_cap_obj_to_user(type,obj) \ - ((type) hurd_cap_obj_to_user_untyped (obj, ({ type t; __alignof__ (*t); }))) - - -/* Find the hurd cap object before the user object OBJ of the pointer - type TYPE. Note that in conjunction with the hurd_cap_obj_from_user - macro below, all of this can and will be computed at compile time, - if optimization is enabled. OBJ already fulfills the alignment - requirement ALIGNMENT. */ -static inline hurd_cap_obj_t -__attribute__((__always_inline__)) -hurd_cap_obj_from_user_untyped (void *obj, size_t alignment) -{ - uintptr_t obj_addr = (uintptr_t) obj; - - obj_addr -= hurd_cap_obj_user_offset (alignment); - - return (hurd_cap_obj_t) obj_addr; -} - -#define hurd_cap_obj_from_user(type,obj) \ - hurd_cap_obj_from_user_untyped (obj, ({ type t; __alignof__ (*t); })) - - -/* Inhibit all RPCs on the capability class CAP_CLASS (which must not - be locked). You _must_ follow up with a hurd_cap_class_resume - operation, and hold at least one reference to the object - continuously until you did so. */ -error_t hurd_cap_class_inhibit (hurd_cap_class_t cap_class); - - -/* Resume RPCs on the class CAP_CLASS and wake-up all waiters. */ -void hurd_cap_class_resume (hurd_cap_class_t cap_class); - - -/* Operations on capability objects. */ - -/* Lock the object OBJ. */ -static inline void -hurd_cap_obj_lock (hurd_cap_obj_t obj) -{ - pthread_mutex_lock (&obj->lock); -} - -/* Unlock the object OBJ, which must be locked. */ -static inline void -hurd_cap_obj_unlock (hurd_cap_obj_t obj) -{ - pthread_mutex_unlock (&obj->lock); -} - - -/* Add a reference to the capability object OBJ. */ -static inline void -hurd_cap_obj_ref (hurd_cap_obj_t obj) -{ - atomic_increment (&obj->refs); -} - - -/* Remove one reference for the capability object OBJ, which must be - locked. Note that the caller must have at least two references for - this capability object when using this function. If this reference - is potentially the last reference (i.e. the caller does not hold - either directly or indirectly another reference to OBJ), - hurd_cap_obj_drop must be used instead. */ -static inline void -hurd_cap_obj_rele (hurd_cap_obj_t obj) -{ - atomic_decrement (&obj->refs); -} - - -/* Remove one reference for the capability object OBJ, which must be - locked, and will be unlocked when the function returns. If this - was the last user of this object, the object is deallocated. */ -void hurd_cap_obj_drop (hurd_cap_obj_t obj); - - -/* Inhibit all RPCs on the capability object OBJ (which must not be - locked). You _must_ follow up with a hurd_cap_obj_resume - operation, and hold at least one reference to the object - continuously until you did so. */ -error_t hurd_cap_obj_inhibit (hurd_cap_obj_t obj); - - -/* Resume RPCs on the capability object OBJ and wake-up all - waiters. */ -void hurd_cap_obj_resume (hurd_cap_obj_t obj); - - -/* Buckets are a set of capabilities, on which RPCs are managed - collectively. */ - -/* Create a new bucket and return it in R_BUCKET. */ -error_t hurd_cap_bucket_create (hurd_cap_bucket_t *r_bucket); - - -/* Free the bucket BUCKET, which must not be used. */ -void hurd_cap_bucket_free (hurd_cap_bucket_t bucket); - - -/* Copy out a capability for the capability OBJ to the client with the - task ID TASK_ID. Returns the capability (valid only for this user) - in *R_CAP, or an error. It is not safe to call this from outside - an RPC on OBJ while the manager is running. */ -error_t hurd_cap_bucket_inject (hurd_cap_bucket_t bucket, hurd_cap_obj_t obj, - hurd_task_id_t task_id, - hurd_cap_handle_t *r_cap); - - -/* If ASYNC is true, allocate worker threads asynchronously whenever - the number of worker threads is exhausted. This is only actually - required for physmem (the physical memory server), to allow to - break out of a dead-lock between physmem and the task server. It - should be unnecessary for any other server. - - The default is to false, which means that worker threads are - allocated synchronously by the manager thread. - - This function should be called before the manager is started with - hurd_cap_bucket_manage_mt. It is only used for the multi-threaded - RPC manager. */ -error_t hurd_cap_bucket_worker_alloc (hurd_cap_bucket_t bucket, bool async); - - -/* Start managing RPCs on the bucket BUCKET. The ROOT capability - object, which must be unlocked and have one reference throughout - the whole time this function runs, is used for bootstrapping client - connections. The GLOBAL_TIMEOUT parameter specifies the number of - seconds until the manager times out (if there are no active users - of capability objects in precious classes). The WORKER_TIMEOUT - parameter specifies the number of seconds until each worker thread - times out (if there are no RPCs processed by the worker thread). - - If this returns ECANCELED, then hurd_cap_bucket_end was called with - the force flag being true while there were still active users. If - this returns without any error, then the timeout expired, or - hurd_cap_bucket_end was called without active users of capability - objects in precious classes. */ -error_t hurd_cap_bucket_manage_mt (hurd_cap_bucket_t bucket, - hurd_cap_obj_t root, - unsigned int global_timeout, - unsigned int worker_timeout); - - -/* Inhibit all RPCs on the capability bucket BUCKET (which must not be - locked). You _must_ follow up with a hurd_cap_bucket_resume (or - hurd_cap_bucket_end) operation. */ -error_t hurd_cap_bucket_inhibit (hurd_cap_bucket_t bucket); - - -/* Resume RPCs on the class CAP_CLASS and wake-up all waiters. */ -void hurd_cap_bucket_resume (hurd_cap_bucket_t bucket); - - -/* Exit from the server loop of the managed capability bucket BUCKET. - This will only succeed if there are no active users, or if the - FORCE flag is set (otherwise it will fail with EBUSY). The bucket - must be inhibited. */ -error_t hurd_cap_bucket_end (hurd_cap_bucket_t bucket, bool force); - - -/* If you want to use other capabilities in an RPC handler beside the - one on which the RPC was invoked, you need to make sure that - inhibition works on those other capabilities and cancel your - operation. For this, the following interfaces are provided. */ - -/* Forward. */ -struct hurd_cap_ctx_cap_use; - -/* Return the number of bytes required for a hurd_cap_ctx_cap_use - structure. */ -size_t hurd_cap_ctx_size (void) __attribute__ ((const)); - -/* The calling thread wishes to execute an RPC on the the handle - HANDLE. The calling thread must already be registered as executing - an RPC. RPC_CTX is the cooresponding RPC context. The function - uses the structure CAP_USE, which must point to the number of bytes - returned by hurd_cap_ctx_size, to store data required by - hurd_cap_ctx_end_cap_use. The capability object corresponding to - HANDLE is locked and returned in *OBJP. - - Returns EINVAL if the capability handle is invalid for the client. - - Returns ENOENT if there is no object associated with handle HANDLE. - - Returns EBAD if the capability is dead. - - Returns EDOM if the object associated with HANDLE is not in class - REQUIRED_CLASS. If no type check is required, it will be skipped - if REQURIED_CLASS is NULL. */ -error_t hurd_cap_ctx_start_cap_use (hurd_cap_rpc_context_t rpc_ctx, - hurd_cap_handle_t handle, - hurd_cap_class_t required_class, - struct hurd_cap_ctx_cap_use *cap_use, - hurd_cap_obj_t *objp); - -/* End the use of the object CAP_USE->OBJ, which must be locked. */ -void hurd_cap_ctx_end_cap_use (hurd_cap_rpc_context_t rpc_ctx, - struct hurd_cap_ctx_cap_use *cap_use); - -#endif /* _HURD_CAP_SERVER_H */ diff --git a/libhurd-cap-server/class-alloc.c b/libhurd-cap-server/class-alloc.c deleted file mode 100644 index b57ca97..0000000 --- a/libhurd-cap-server/class-alloc.c +++ /dev/null @@ -1,64 +0,0 @@ -/* class-alloc.c - Allocate a capability object. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include <hurd/slab.h> -#include <hurd/cap-server.h> - - -/* Allocate a new capability object in the class CAP_CLASS. The new - capability object is locked and has one reference. It will be - returned in R_OBJ. If the allocation fails, an error value will be - returned. */ -error_t -hurd_cap_class_alloc (hurd_cap_class_t cap_class, hurd_cap_obj_t *r_obj) -{ - error_t err; - void *new_obj; - hurd_cap_obj_t obj; - - err = hurd_slab_alloc (&cap_class->obj_space, &new_obj); - if (err) - return err; - obj = new_obj; - - /* Let the user do their extra initialization. */ - if (cap_class->obj_alloc) - { - err = (*cap_class->obj_alloc) (cap_class, obj); - if (err) - { - hurd_slab_dealloc (&cap_class->obj_space, obj); - return err; - } - } - - /* Now take the lock. */ - hurd_cap_obj_lock (obj); - - *r_obj = obj; - return 0; -} diff --git a/libhurd-cap-server/class-create.c b/libhurd-cap-server/class-create.c deleted file mode 100644 index 2f4c16a..0000000 --- a/libhurd-cap-server/class-create.c +++ /dev/null @@ -1,75 +0,0 @@ -/* class-create.c - Create a capability class. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> - -#include <hurd/cap-server.h> - - -/* Create a new capability class for objects allocating SIZE bytes for - the user object with alignment ALIGNMENT (i.e. size does NOT - include the struct hurd_cap_obj which is placed at the beginning of - each capability object). - - The callback OBJ_INIT is used whenever a capability object in this - class is created. The callback OBJ_REINIT is used whenever a - capability object in this class is deallocated and returned to the - slab. OBJ_REINIT should return a capability object that is not - used anymore into the same state as OBJ_INIT does for a freshly - allocated object. OBJ_DESTROY should deallocate all resources for - this capablity object. Note that if OBJ_INIT or OBJ_REINIT fails, - the object is considered to be fully destroyed. No extra call to - OBJ_DESTROY will be made for such objects. - - The new capability class is returned in R_CLASS. If the creation - fails, an error value will be returned. */ -error_t -hurd_cap_class_create_untyped (size_t size, size_t alignment, - hurd_cap_obj_init_t obj_init, - hurd_cap_obj_alloc_t obj_alloc, - hurd_cap_obj_reinit_t obj_reinit, - hurd_cap_obj_destroy_t obj_destroy, - hurd_cap_class_demuxer_t demuxer, - hurd_cap_class_t *r_class) -{ - error_t err; - hurd_cap_class_t cap_class = malloc (sizeof (struct hurd_cap_class)); - - if (!cap_class) - return errno; - - err = hurd_cap_class_init_untyped (cap_class, size, alignment, obj_init, - obj_alloc, obj_reinit, obj_destroy, - demuxer); - if (err) - { - free (cap_class); - return err; - } - - *r_class = cap_class; - return 0; -} diff --git a/libhurd-cap-server/class-destroy.c b/libhurd-cap-server/class-destroy.c deleted file mode 100644 index 116d99a..0000000 --- a/libhurd-cap-server/class-destroy.c +++ /dev/null @@ -1,58 +0,0 @@ -/* class-destroy.c - Destroy a capability class. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> - -#include <hurd/cap-server.h> - - -/* Destroy the capability class CAP_CLASS and release all associated - resources. Note that this is only allowed if there are no - capability objects in use, and if the capability class is not used - by a capability server. This function assumes that the class has - been initialized with hurd_cap_class_init. */ -error_t -hurd_cap_class_destroy (hurd_cap_class_t cap_class) -{ - error_t err = 0; - - /* FIXME: This function needs to be revised. We need to take the - locks, and if only for memory synchronization. */ - - /* This will fail if there are still allocated capability - objects. */ - err = hurd_slab_destroy (&cap_class->obj_space); - if (err) - return err; - - /* At this point, destruction will succeed. */ - pthread_cond_destroy (&cap_class->cond); - pthread_mutex_destroy (&cap_class->lock); - pthread_mutex_destroy (&cap_class->obj_cond_lock); - pthread_cond_destroy (&cap_class->obj_cond); - - return 0; -} diff --git a/libhurd-cap-server/class-free.c b/libhurd-cap-server/class-free.c deleted file mode 100644 index 6c5c0be..0000000 --- a/libhurd-cap-server/class-free.c +++ /dev/null @@ -1,48 +0,0 @@ -/* class-free.c - Free a capability class. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> - -#include <hurd/cap-server.h> - - -/* Destroy the capability class CAP_CLASS and release all associated - resources. Note that this is only allowed if there are no - capability objects in use, and if the capability class is not used - by a capability server. This function assumes that the class was - created with hurd_cap_class_create. */ -error_t -hurd_cap_class_free (hurd_cap_class_t cap_class) -{ - error_t err; - - err = hurd_cap_class_destroy (cap_class); - if (err) - return err; - - free (cap_class); - return 0; -} diff --git a/libhurd-cap-server/class-inhibit.c b/libhurd-cap-server/class-inhibit.c deleted file mode 100644 index ea2a663..0000000 --- a/libhurd-cap-server/class-inhibit.c +++ /dev/null @@ -1,114 +0,0 @@ -/* class-inhibit.c - Inhibit RPCs on a capability class. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Inhibit all RPCs on the capability class CAP_CLASS (which must not - be locked). You _must_ follow up with a hurd_cap_class_resume - operation, and hold at least one reference to the object - continuously until you did so. */ -error_t -hurd_cap_class_inhibit (hurd_cap_class_t cap_class) -{ - error_t err; - - pthread_mutex_lock (&cap_class->lock); - - /* First wait until any other inhibitor has resumed the class. If - this function is called within an RPC, we are going to be - canceled anyway. Otherwise, it ensures that class inhibitions - are fully serialized (per class). */ - while (cap_class->state != _HURD_CAP_STATE_GREEN) - { - err = hurd_cond_wait (&cap_class->cond, &cap_class->lock); - if (err) - { - /* We have been canceled. */ - pthread_mutex_unlock (&cap_class->lock); - return err; - } - } - - /* Now it is our turn to inhibit the class. */ - cap_class->cond_waiter = pthread_self (); - - if (_hurd_cap_class_cond_busy (cap_class)) - { - _hurd_cap_list_item_t pending_rpc = cap_class->pending_rpcs; - - /* There are still pending RPCs (beside us). Cancel them. */ - while (pending_rpc) - { - if (pending_rpc->thread != cap_class->cond_waiter) - pthread_cancel (pending_rpc->thread); - pending_rpc = pending_rpc->next; - } - - /* Indicate that we would like to know when they have gone. */ - cap_class->state = _HURD_CAP_STATE_YELLOW; - - /* The last one will shut the door. */ - do - { - err = hurd_cond_wait (&cap_class->cond, &cap_class->lock); - if (err) - { - /* We have been canceled ourselves. Give up. */ - cap_class->state = _HURD_CAP_STATE_GREEN; - pthread_mutex_unlock (&cap_class->lock); - return err; - } - } - while (cap_class->state != _HURD_CAP_STATE_RED); - } - else - cap_class->state = _HURD_CAP_STATE_RED; - - /* Now all pending RPCs have been canceled and are completed (except - us), and all incoming RPCs are inhibited. */ - pthread_mutex_unlock (&cap_class->lock); - - return 0; -} - - -/* Resume RPCs on the class CAP_CLASS and wake-up all waiters. */ -void -hurd_cap_class_resume (hurd_cap_class_t cap_class) -{ - pthread_mutex_lock (&cap_class->lock); - - cap_class->state = _HURD_CAP_STATE_GREEN; - - /* Broadcast the change to all potential waiters. */ - pthread_cond_broadcast (&cap_class->cond); - - pthread_mutex_unlock (&cap_class->lock); -} diff --git a/libhurd-cap-server/class-init.c b/libhurd-cap-server/class-init.c deleted file mode 100644 index 150fa96..0000000 --- a/libhurd-cap-server/class-init.c +++ /dev/null @@ -1,180 +0,0 @@ -/* class-init.c - Initialize a capability class. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <assert.h> -#include <stdlib.h> -#include <pthread.h> - -#include <hurd/slab.h> -#include <hurd/cap-server.h> - - -/* Initialize the slab object pointed to by BUFFER. HOOK is as - provided to hurd_slab_create. */ -static error_t -_hurd_cap_obj_constructor (void *hook, void *buffer) -{ - hurd_cap_class_t cap_class = (hurd_cap_class_t) hook; - hurd_cap_obj_t obj = (hurd_cap_obj_t) buffer; - error_t err; - - /* First do our own initialization. */ - obj->cap_class = cap_class; - - err = pthread_mutex_init (&obj->lock, 0); - if (err) - return err; - - obj->refs = 1; - obj->state = _HURD_CAP_STATE_GREEN; - obj->pending_rpcs = NULL; - /* The member COND_WAITER does not need to be initialized. */ - obj->clients = NULL; - - /* Then do the user part, if necessary. */ - if (cap_class->obj_init) - { - err = (*cap_class->obj_init) (cap_class, obj); - if (err) - { - pthread_mutex_destroy (&obj->lock); - return err; - } - } - - return 0; -} - - -/* Destroy the slab object pointed to by BUFFER. HOOK is as provided - to hurd_slab_create. */ -static void -_hurd_cap_obj_destructor (void *hook, void *buffer) -{ - hurd_cap_class_t cap_class = (hurd_cap_class_t) hook; - hurd_cap_obj_t obj = (hurd_cap_obj_t) buffer; - - if (cap_class->obj_destroy) - (*cap_class->obj_destroy) (cap_class, obj); - - pthread_mutex_destroy (&obj->lock); -} - - -/* Same as hurd_cap_class_create, but doesn't allocate the storage for - CAP_CLASS. Instead, you have to provide it. */ -error_t -hurd_cap_class_init_untyped (hurd_cap_class_t cap_class, - size_t size, size_t alignment, - hurd_cap_obj_init_t obj_init, - hurd_cap_obj_alloc_t obj_alloc, - hurd_cap_obj_reinit_t obj_reinit, - hurd_cap_obj_destroy_t obj_destroy, - hurd_cap_class_demuxer_t demuxer) -{ - error_t err; - - /* The alignment requirements must be a power of 2. */ - assert ((alignment & (alignment - 1)) == 0 - || ! "hurd_cap_class_init_untyped: " - "requested alignment not a power of 2"); - - /* Find the smallest alignment requirement common to the user object - and a struct hurd_cap_obj. Since both are required to be a power - of 2, we need simply take the larger one. */ - if (alignment < __alignof__(struct hurd_cap_obj)) - alignment = __alignof__(struct hurd_cap_obj); - - size += hurd_cap_obj_user_offset (alignment); - - /* Capability object management. */ - - cap_class->obj_init = obj_init; - cap_class->obj_alloc = obj_alloc; - cap_class->obj_reinit = obj_reinit; - cap_class->obj_destroy = obj_destroy; - - err = hurd_slab_init (&cap_class->obj_space, size, alignment, NULL, NULL, - _hurd_cap_obj_constructor, _hurd_cap_obj_destructor, - cap_class); - if (err) - goto err_obj_space; - - err = pthread_cond_init (&cap_class->obj_cond, NULL); - if (err) - goto err_obj_cond; - - err = pthread_mutex_init (&cap_class->obj_cond_lock, NULL); - if (err) - goto err_obj_cond_lock; - - - /* Class management. */ - - cap_class->demuxer = demuxer; - - err = pthread_mutex_init (&cap_class->lock, NULL); - if (err) - goto err_lock; - - cap_class->state = _HURD_CAP_STATE_GREEN; - - err = pthread_cond_init (&cap_class->cond, NULL); - if (err) - goto err_cond; - - /* The cond_waiter member doesn't need to be initialized. It is - only valid when CAP_CLASS->STATE is _HURD_CAP_STATE_YELLOW. */ - - cap_class->pending_rpcs = NULL; - - /* FIXME: Add the class to the list of classes to be served by - RPCs. */ - - return 0; - - /* This is provided here in case you add more initialization to the - end of the above code. */ -#if 0 - pthread_cond_destroy (&cap_class->cond); -#endif - - err_cond: - pthread_mutex_destroy (&cap_class->lock); - - err_lock: - pthread_mutex_destroy (&cap_class->obj_cond_lock); - - err_obj_cond_lock: - pthread_cond_destroy (&cap_class->obj_cond); - - err_obj_cond: - /* This can not fail at this point. */ - hurd_slab_destroy (&cap_class->obj_space); - - err_obj_space: - return err; -} diff --git a/libhurd-cap-server/client-create.c b/libhurd-cap-server/client-create.c deleted file mode 100644 index ac8c54a..0000000 --- a/libhurd-cap-server/client-create.c +++ /dev/null @@ -1,213 +0,0 @@ -/* client-create.c - Create a capability client. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <assert.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Client management code. */ - -/* Allocate a new capability client structure for the slab cache. */ -static error_t -_hurd_cap_client_constructor (void *hook, void *buffer) -{ - _hurd_cap_client_t client = (_hurd_cap_client_t) buffer; - error_t err; - - err = pthread_mutex_init (&client->lock, NULL); - if (err) - return err; - - client->state = _HURD_CAP_STATE_GREEN; - client->pending_rpcs = NULL; - - /* Capabilities are mapped to clients many to many, so we can not - use a location pointer. However, this is not critical as - removing an entry only blocks out RPCs for the same client, and - not others. */ - hurd_ihash_init (&client->caps_reverse, HURD_IHASH_NO_LOCP); - - return 0; - - /* This is provided here in case you add more initialization to the - end of the above code. */ -#if 0 - pthread_mutex_destroy (&client->lock); - - return err; -#endif -} - - -/* Allocate a new capability client structure for the slab cache. */ -static void -_hurd_cap_client_destructor (void *hook, void *buffer) -{ - _hurd_cap_client_t client = (_hurd_cap_client_t) buffer; - - hurd_ihash_destroy (&client->caps_reverse); - hurd_table_destroy (&client->caps); - pthread_mutex_destroy (&client->lock); -} - - -/* The global slab for all capability clients. */ -struct hurd_slab_space _hurd_cap_client_space - = HURD_SLAB_SPACE_INITIALIZER (struct _hurd_cap_client, NULL, NULL, - _hurd_cap_client_constructor, - _hurd_cap_client_destructor, NULL); - - -static error_t -_hurd_cap_client_alloc (hurd_task_id_t task_id, - _hurd_cap_client_t *r_client) -{ - error_t err; - void *new_client; - _hurd_cap_client_t client; - - err = hurd_slab_alloc (&_hurd_cap_client_space, &new_client); - if (err) - return err; - - client = new_client; - - /* CLIENT->id will be initialized by the caller when adding the - client to the client table of the class. */ - client->task_id = task_id; - - err = hurd_table_init (&client->caps, sizeof (_hurd_cap_obj_entry_t)); - if (err) - { - free (client); - return err; - } - - /* FIXME: We need to acquire a task info capability here. The task - death notifications have been suspended by the caller. */ - - *r_client = client; - return 0; -} - - -/* Look up the client with the task ID TASK in the bucket BUCKET, and - return it in R_CLIENT, with one additional reference. If it is not - found, create it. */ -error_t -__attribute__((visibility("hidden"))) -_hurd_cap_client_create (hurd_cap_bucket_t bucket, - hurd_task_id_t task_id, - _hurd_cap_client_t *r_client) -{ - error_t err = 0; - _hurd_cap_client_t client; - - pthread_mutex_lock (&bucket->lock); - client = (_hurd_cap_client_t) hurd_ihash_find (&bucket->clients_reverse, - task_id); - if (client) - { - if (client->dead) - err = EINVAL; /* FIXME: A more appropriate code? */ - else - { - client->refs++; - *r_client = client; - } - pthread_mutex_unlock (&bucket->lock); - return err; - } - pthread_mutex_unlock (&bucket->lock); - - /* The client is not yet registered. Block out processing task - death notifications, create a new client structure, and then - enter it into the table before resuming task death - notifications. */ - hurd_task_death_notify_suspend (); - err = _hurd_cap_client_alloc (task_id, r_client); - if (err) - { - hurd_task_death_notify_resume (); - return err; - } - - pthread_mutex_lock (&bucket->lock); - /* Since we dropped the bucket lock during the allocation (which is - potentially long) we need to check that somebody else didn't - already allocate a client data structure. If so, we can just use - that. Otherwise, we continue. */ - client = (_hurd_cap_client_t) hurd_ihash_find (&bucket->clients_reverse, - task_id); - if (client) - { - if (client->dead) - { - err = EINVAL; /* FIXME: A more appropriate code? */ - pthread_mutex_unlock (&bucket->lock); - } - else - { - /* Somebody else was indeed faster. Use the existing entry. */ - client->refs++; - pthread_mutex_unlock (&bucket->lock); - _hurd_cap_client_dealloc (bucket, *r_client); - *r_client = client; - } - return err; - } - - client = *r_client; - - /* One reference for the fact that the client task lives, one for - the caller. */ - client->refs = 2; - - err = hurd_table_enter (&bucket->clients, &client, &client->id); - if (!err) - { - err = hurd_ihash_add (&bucket->clients_reverse, task_id, client); - if (err) - hurd_table_remove (&bucket->clients, client->id); - } - if (err) - { - pthread_mutex_unlock (&bucket->lock); - hurd_task_death_notify_resume (); - - _hurd_cap_client_dealloc (bucket, client); - return err; - } - pthread_mutex_unlock (&bucket->lock); - hurd_task_death_notify_resume (); - - *r_client = client; - - return 0; -} diff --git a/libhurd-cap-server/client-inhibit.c b/libhurd-cap-server/client-inhibit.c deleted file mode 100644 index 2228b5f..0000000 --- a/libhurd-cap-server/client-inhibit.c +++ /dev/null @@ -1,157 +0,0 @@ -/* client-inhibit.c - Inhibit RPCs on a capability client. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Inhibit all RPCs on the capability client CLIENT (which must not be - locked) in the capability bucket BUCKET. You _must_ follow up - with a hurd_cap_client_resume operation, and hold at least one - reference to the object continuously until you did so. */ -error_t -_hurd_cap_client_inhibit (hurd_cap_bucket_t bucket, _hurd_cap_client_t client) -{ - error_t err; - - /* First take the bucket-wide lock for conditions on capability - client states. */ - pthread_mutex_lock (&bucket->client_cond_lock); - - /* Then lock the client to check its state. */ - pthread_mutex_lock (&client->lock); - - /* First wait until any other inhibitor has resumed the capability - client. This ensures that capability client inhibitions are - fully serialized (per capability client). */ - while (client->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&client->lock); - err = hurd_cond_wait (&bucket->client_cond, - &bucket->client_cond_lock); - if (err) - { - /* We have been canceled. */ - pthread_mutex_unlock (&bucket->client_cond_lock); - return err; - } - pthread_mutex_lock (&client->lock); - } - - /* Now it is our turn to inhibit the capability client. */ - client->cond_waiter = pthread_self (); - - if (_hurd_cap_client_cond_busy (client)) - { - _hurd_cap_list_item_t pending_rpc = client->pending_rpcs; - - /* There are still pending RPCs (beside us). Cancel them. */ - while (pending_rpc) - { - if (pending_rpc->thread != client->cond_waiter) - pthread_cancel (pending_rpc->thread); - pending_rpc = pending_rpc->next; - } - - /* Indicate that we would like to know when they have gone. */ - client->state = _HURD_CAP_STATE_YELLOW; - - /* The last one will shut the door. */ - do - { - pthread_mutex_unlock (&client->lock); - err = hurd_cond_wait (&bucket->client_cond, - &bucket->client_cond_lock); - if (err) - { - /* We have been canceled ourselves. Give up. */ - client->state = _HURD_CAP_STATE_GREEN; - pthread_mutex_unlock (&bucket->client_cond_lock); - return err; - } - pthread_mutex_lock (&client->lock); - } - while (client->state != _HURD_CAP_STATE_RED); - } - else - client->state = _HURD_CAP_STATE_RED; - - /* Now all pending RPCs have been canceled and are completed (except - us), and all incoming RPCs are inhibited. */ - pthread_mutex_unlock (&client->lock); - pthread_mutex_unlock (&bucket->client_cond_lock); - - return 0; -} - - -/* Resume RPCs on the capability client CLIENT in the bucket BUCKET - and wake-up all waiters. */ -void -_hurd_cap_client_resume (hurd_cap_bucket_t bucket, _hurd_cap_client_t client) -{ - pthread_mutex_lock (&bucket->client_cond_lock); - pthread_mutex_lock (&client->lock); - - client->state = _HURD_CAP_STATE_GREEN; - - /* Broadcast the change to all potential waiters. */ - pthread_cond_broadcast (&bucket->client_cond); - - pthread_mutex_unlock (&client->lock); - pthread_mutex_unlock (&bucket->client_cond_lock); -} - - -/* End RPCs on the capability client CLIENT in the bucket BUCKET and - wake-up all waiters. */ -void -_hurd_cap_client_end (hurd_cap_bucket_t bucket, _hurd_cap_client_t client) -{ - pthread_mutex_lock (&bucket->client_cond_lock); - pthread_mutex_lock (&bucket->lock); - - client->state = _HURD_CAP_STATE_BLACK; - - /* Broadcast the change to all potential waiters. Even though the - task is dead now, there is a race condition where we will process - one spurious incoming RPC which is blocked on the inhibited - state. So we wake up such threads, they will then go away - quickly. - - Note that this does not work reliably for still living clients: - They may bombard us with RPCs and thus keep the reference count - of the client in the bucket table above 0 all the time, even in - the _HURD_CAP_STATE_BLACK state. This is the reason that this - interface is only for internal use (by - _hurd_cap_client_death). */ - pthread_cond_broadcast (&bucket->client_cond); - - pthread_mutex_unlock (&bucket->lock); - pthread_mutex_unlock (&bucket->client_cond_lock); -} diff --git a/libhurd-cap-server/client-release.c b/libhurd-cap-server/client-release.c deleted file mode 100644 index 57d3796..0000000 --- a/libhurd-cap-server/client-release.c +++ /dev/null @@ -1,192 +0,0 @@ -/* client-release.c - Release a capability client. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include <compiler.h> - -#include "cap-server-intern.h" - - -/* Deallocate the connection client CLIENT. */ -void -_hurd_cap_client_dealloc (hurd_cap_bucket_t bucket, _hurd_cap_client_t client) -{ - unsigned int nr_caps = 0; - - /* This function is only invoked if the reference count for the - client entry in the client table of the class drops to 0, and - after the table entry was removed. Usually, the last reference - is removed by the task death notification handler. - - At that point, there are no more pending RPCs for this client (if - there were, there would be a reference for each of them). This - also means that all capability IDs have at most one internal - reference, the one for all external references. */ - - /* Note that although the client has been removed from the clients - table in the class, there are still back-references for each and - every capability object in our capability table caps. These - capability entries all count as references to ourself. They are - used for example if a capability is revoked. It is important to - realize that such a revocation can happen anytime as long as - there are still valid capability objects in the caps table of the - client. - - So, to correctly release those references, we have to look up - each capability object properly, acquiring our own internal - reference for it, then we have to unlock the client to lock the - capability object, to finally revoke our own capability and - release the capability object reference. Only then can we - reacquire our own lock and go on to the next capability. While - we do not hold our lock, more capabilities can be revoked by - other concurrent operations. However, no new capabilities are - added, so one pass through the table is enough. */ - - pthread_mutex_lock (&client->lock); - - /* Release all capability objects held by this user. Because we - have to honor the locking order, this takes a while. */ - HURD_TABLE_ITERATE (&client->caps, idx) - { - _hurd_cap_obj_entry_t entry; - - entry = *((_hurd_cap_obj_entry_t *) - HURD_TABLE_LOOKUP (&client->caps, idx)); - - /* If there were no external references, the last internal - reference would have been released before we get here. */ - assert (entry->external_refs); - - nr_caps++; - - /* The number of internal references is either one or zero. If - it is one, then the capability is not revoked yet, so we have - to do it. If it is zero, then the capability is revoked - (dead), and we only have to clear the table entry. */ - if (!entry->dead) - { - hurd_cap_obj_t cap_obj = entry->cap_obj; - - assert (entry->internal_refs == 1); - - /* Acquire an internal reference to prevent that our own - reference to the capability object is removed by a - concurrent revocation as soon as we unlock the client. - After all, the existing internal reference belongs to the - capability object, and not to us. */ - entry->internal_refs++; - pthread_mutex_unlock (&client->lock); - - pthread_mutex_lock (&cap_obj->lock); - /* Check if we should revoke it, or if somebody else did already. */ - if (!entry->dead) - { - int found; - - /* We should revoke it. */ - pthread_mutex_lock (&client->lock); - found = hurd_ihash_remove (&client->caps_reverse, - (hurd_ihash_key_t) cap_obj); - assert (found); - entry->dead = 1; - - assert (entry->internal_refs == 2); - entry->internal_refs--; - pthread_mutex_unlock (&client->lock); - - /* FIXME: Remove it from the capabilities client list. */ - } - pthread_mutex_unlock (&cap_obj->lock); - - pthread_mutex_lock (&client->lock); - /* Now we can drop the capability object below. */ - assert (entry->dead); - assert (entry->internal_refs == 1); - assert (entry->external_refs); - } - else - { - /* If the capability is dead, we can simply drop it below. */ - assert (entry->internal_refs == 0); - entry->internal_refs = 1; - } - - entry->dead = 0; - /* ENTRY->internal_refs is 1. */ - entry->external_refs = 1; - - /* Remove the entry. */ - hurd_slab_dealloc (&_hurd_cap_obj_entry_space, entry); - hurd_table_remove (&client->caps, idx); - } - - /* After all this ugly work, the rest is trivial. */ - if (client->state != _HURD_CAP_STATE_GREEN) - client->state = _HURD_CAP_STATE_GREEN; - - assert (client->pending_rpcs == NULL); - - /* FIXME: Release the task info capability here. */ - - /* FIXME: It would be a good idea to shrink the empty table and - empty hash here, to reclaim resources and be able to eventually - enforce a per-client quota. */ - pthread_mutex_unlock (&client->lock); - - pthread_mutex_lock (&bucket->lock); - bucket->nr_caps -= nr_caps; - pthread_mutex_unlock (&bucket->lock); - - hurd_slab_dealloc (&_hurd_cap_client_space, client); -} - - -/* Release a reference for the client with the ID IDX in bucket - BUCKET. */ -void -_hurd_cap_client_release (hurd_cap_bucket_t bucket, _hurd_cap_client_id_t idx) -{ - _hurd_cap_client_t client; - - pthread_mutex_lock (&bucket->lock); - client = *(_hurd_cap_client_t *) HURD_TABLE_LOOKUP (&bucket->clients, idx); - - if (EXPECT_TRUE (client->refs > 1)) - { - client->refs--; - pthread_mutex_unlock (&bucket->lock); - } - else - { - hurd_table_remove (&bucket->clients, idx); - hurd_ihash_locp_remove (&bucket->clients_reverse, client->locp); - - pthread_mutex_unlock (&bucket->lock); - _hurd_cap_client_dealloc (bucket, client); - } -} diff --git a/libhurd-cap-server/ctx-cap-use.c b/libhurd-cap-server/ctx-cap-use.c deleted file mode 100644 index 3758c19..0000000 --- a/libhurd-cap-server/ctx-cap-use.c +++ /dev/null @@ -1,278 +0,0 @@ -/* ctx-cap-use.c - Use capabilities within an RPC context. - Copyright (C) 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> - -#include <hurd/cap-server.h> - -#include <compiler.h> - -#include "cap-server-intern.h" - - -/* Return the number of bytes required for a hurd_cap_ctx_cap_use - structure. */ -size_t -hurd_cap_ctx_size (void) -{ - return sizeof (struct hurd_cap_ctx_cap_use); -} - -/* If you want to use other capabilities in an RPC handler beside the - one on which the RPC was invoked, you need to make sure that - inhibition works on those other capabilities and cancel your - operation. For this, the following interfaces are provided. */ - -/* The calling thread wishes to execute an RPC on the the handle - HANDLE. The calling thread must already be registered as executing - an RPC. RPC_CTX is the cooresponding RPC context. The function - uses the structure CAP_USE, which must point to the number of bytes - returned by hurd_cap_ctx_size, to store data required by - hurd_cap_ctx_end_cap_use. The capability object corresponding to - HANDLE is locked and returned in *OBJP. - - Returns EINVAL if the capability handle is invalid for the client. - - Returns ENOENT if there is no object associated with handle HANDLE. - - Returns EBAD if the capability is dead. - - Returns EDOM if the object associated with HANDLE is not in class - REQUIRED_CLASS. If no type check is required, it will be skipped - if REQURIED_CLASS is NULL. */ -error_t -hurd_cap_ctx_start_cap_use (hurd_cap_rpc_context_t rpc_ctx, - hurd_cap_handle_t handle, - hurd_cap_class_t required_class, - struct hurd_cap_ctx_cap_use *cap_use, - hurd_cap_obj_t *objp) -{ - error_t err = 0; - hurd_cap_bucket_t bucket = rpc_ctx->bucket; - _hurd_cap_client_t client = rpc_ctx->client; - hurd_cap_obj_t obj; - hurd_cap_class_t cap_class; - _hurd_cap_obj_entry_t obj_entry; - _hurd_cap_obj_entry_t *obj_entryp; - - - /* HANDLE must belong to the same client as RPC_CTX->HANDLE. */ - if (_hurd_cap_client_id (handle) != _hurd_cap_client_id (rpc_ctx->handle)) - return EINVAL; - - pthread_mutex_lock (&client->lock); - - /* Look up the object. */ - obj_entryp = (_hurd_cap_obj_entry_t *) - hurd_table_lookup (&client->caps, _hurd_cap_id (handle)); - if (!obj_entryp) - err = ENOENT; - else - { - cap_use->_obj_entry = obj_entry = *obj_entryp; - - if (EXPECT_FALSE (!obj_entry->external_refs)) - err = ENOENT; - else if (EXPECT_FALSE (obj_entry->dead)) - err = EBADF; - else - { - obj_entry->internal_refs++; - *objp = obj = obj_entry->cap_obj; - } - } - pthread_mutex_unlock (&client->lock); - - if (err) - /* Either the capability ID is invalid, or it was revoked. */ - return err; - - /* If HANDLE and RPC_CTX->HANDLE are the same, we are done. */ - if (EXPECT_FALSE (_hurd_cap_id (handle) == _hurd_cap_id (rpc_ctx->handle))) - { - assert (obj == rpc_ctx->obj); - return 0; - } - - /* At this point, CAP and OBJ are valid and we have one internal - reference to the capability entry. */ - - cap_class = obj->cap_class; - - if (required_class && cap_class != required_class) - { - err = EINVAL; - goto client_cleanup; - } - - if (cap_class != rpc_ctx->obj->cap_class) - /* The capability class is not the same as the first caps. We - need to add ourself to the cap class pending rpc list. */ - { - pthread_mutex_lock (&cap_class->lock); - /* First, we have to check if the class is inhibited, and if it is, - we have to wait until it is uninhibited. */ - while (!err && cap_class->state != _HURD_CAP_STATE_GREEN) - err = hurd_cond_wait (&cap_class->cond, &cap_class->lock); - if (err) - { - /* Canceled. */ - pthread_mutex_unlock (&cap_class->lock); - goto client_cleanup; - } - - /* Now add ourself to the pending rpc list of the class */ - cap_use->_worker_class.thread = pthread_self (); - cap_use->_worker_class.tid = l4_myself (); - _hurd_cap_list_item_add (&cap_class->pending_rpcs, - &cap_use->_worker_class); - - pthread_mutex_unlock (&cap_class->lock); - } - - pthread_mutex_lock (&obj->lock); - /* First, we have to check if the object is inhibited, and if it is, - we have to wait until it is uninhibited. */ - if (obj->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&obj->lock); - pthread_mutex_lock (&cap_class->obj_cond_lock); - pthread_mutex_lock (&obj->lock); - while (!err && obj->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&obj->lock); - err = hurd_cond_wait (&cap_class->obj_cond, - &cap_class->obj_cond_lock); - pthread_mutex_lock (&obj->lock); - } - pthread_mutex_unlock (&cap_class->obj_cond_lock); - } - if (err) - { - /* Canceled. */ - pthread_mutex_unlock (&obj->lock); - goto class_cleanup; - } - - /* Now check if the client still has the capability, or if it was - revoked. */ - pthread_mutex_lock (&client->lock); - if (obj_entry->dead) - err = EBADF; - pthread_mutex_unlock (&client->lock); - if (err) - { - /* The capability was revoked in the meantime. */ - pthread_mutex_unlock (&obj->lock); - goto class_cleanup; - } - - cap_use->_worker_obj.thread = pthread_self (); - cap_use->_worker_obj.tid = l4_myself (); - _hurd_cap_list_item_add (&cap_class->pending_rpcs, &cap_use->_worker_obj); - - /* At this point, we have looked up the capability, acquired an - internal reference for its entry in the client table (which - implicitely keeps a reference acquired for the object itself), - acquired a reference for the capability client in the bucket, and - have added an item to the pending_rpcs lists in the class (if - necessary) and object. The object is locked. */ - - return 0; - - class_cleanup: - if (cap_use->_obj_entry->cap_obj->cap_class != rpc_ctx->obj->cap_class) - /* Different classes. */ - { - pthread_mutex_lock (&cap_class->lock); - _hurd_cap_list_item_remove (&cap_use->_worker_class); - _hurd_cap_class_cond_check (cap_class); - pthread_mutex_unlock (&cap_class->lock); - } - - client_cleanup: - pthread_mutex_lock (&client->lock); - - /* You are not allowed to revoke a capability while there are - pending RPCs on it. This is the reason we know that there must - be at least one extra internal reference. FIXME: For - cleanliness, this could still call some inline function that does - the decrement. The assert can be a hint to the compiler to - optimize the inline function expansion anyway. */ - assert (!obj_entry->dead); - assert (obj_entry->internal_refs > 1); - obj_entry->internal_refs--; - pthread_mutex_unlock (&client->lock); - - return err; -} - - -/* End the use of the object CAP_USE->OBJ, which must be locked. */ -void -hurd_cap_ctx_end_cap_use (hurd_cap_rpc_context_t rpc_ctx, - struct hurd_cap_ctx_cap_use *cap_use) -{ - _hurd_cap_obj_entry_t entry = cap_use->_obj_entry; - hurd_cap_obj_t obj = entry->cap_obj; - _hurd_cap_client_t client = rpc_ctx->client; - - /* Is this an additional use of the main capability object? */ - if (EXPECT_TRUE (obj != rpc_ctx->obj)) - /* No. */ - { - hurd_cap_class_t cap_class = obj->cap_class; - - /* End the RPC on the object. */ - _hurd_cap_list_item_remove (&cap_use->_worker_obj); - _hurd_cap_obj_cond_check (obj); - - if (cap_class != rpc_ctx->obj->cap_class) - /* The capability object is in a different class from the primary - capability object. */ - { - pthread_mutex_lock (&cap_class->lock); - _hurd_cap_list_item_remove (&cap_use->_worker_class); - _hurd_cap_class_cond_check (cap_class); - pthread_mutex_unlock (&cap_class->lock); - } - } - - hurd_cap_obj_unlock (obj); - - /* You are not allowed to revoke a capability while there are - pending RPCs on it. This is the reason why we know that there - must be at least one extra internal reference. FIXME: For - cleanliness, this could still call some inline function that does - the decrement. The assert can be a hint to the compiler to - optimize the inline function expansion anyway. */ - - pthread_mutex_lock (&client->lock); - assert (!entry->dead); - assert (entry->internal_refs > 1); - entry->internal_refs--; - pthread_mutex_unlock (&client->lock); -} diff --git a/libhurd-cap-server/headers.m4 b/libhurd-cap-server/headers.m4 deleted file mode 100644 index 886469e..0000000 --- a/libhurd-cap-server/headers.m4 +++ /dev/null @@ -1,13 +0,0 @@ -# headers.m4 - Autoconf snippets to install links for header files. -# Copyright 2003 Free Software Foundation, Inc. -# Written by Marcus Brinkmann <marcus@gnu.org>. -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This file is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -AC_CONFIG_LINKS([include/hurd/cap-server.h:libhurd-cap-server/cap-server.h]) diff --git a/libhurd-cap-server/obj-copy-out.c b/libhurd-cap-server/obj-copy-out.c deleted file mode 100644 index c0e8b93..0000000 --- a/libhurd-cap-server/obj-copy-out.c +++ /dev/null @@ -1,121 +0,0 @@ -/* obj-copy-out.c - Copy out a capability to a client. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Copy out a capability for the capability OBJ to the user CLIENT. - Returns the capability ID (valid only for this user) in *R_ID, or - an error. OBJ must be locked. Note: No internal reference for - this capability is allocated for the caller. */ -error_t -_hurd_cap_obj_copy_out (hurd_cap_obj_t obj, hurd_cap_bucket_t bucket, - _hurd_cap_client_t client, _hurd_cap_id_t *r_id) -{ - void *new_entry; - _hurd_cap_obj_entry_t entry; - - pthread_mutex_lock (&client->lock); - entry = (_hurd_cap_obj_entry_t) hurd_ihash_find (&client->caps_reverse, - (hurd_ihash_key_t) obj); - - if (entry) - { - entry->external_refs++; - *r_id = entry->id; - pthread_mutex_unlock (&client->lock); - return 0; - } - else - { - _hurd_cap_obj_entry_t entry_check; - error_t err; - - pthread_mutex_unlock (&client->lock); - err = hurd_slab_alloc (&_hurd_cap_obj_entry_space, &new_entry); - if (err) - return err; - entry = new_entry; - - entry->cap_obj = obj; - /* ID is filled in when adding the object to the table. */ - /* CLIENT_ITEM is filled after the object has been entered. */ - /* DEAD is 0 for initialized objects. */ - /* INTERNAL_REFS is 1 for initialized objects. */ - /* EXTERNAL_REFS is 1 for initialized objects. */ - - pthread_mutex_lock (&client->lock); - entry_check = hurd_ihash_find (&client->caps_reverse, - (hurd_ihash_key_t) obj); - if (entry_check) - { - /* Somebody else was faster. */ - entry_check->external_refs++; - *r_id = entry_check->id; - pthread_mutex_unlock (&client->lock); - hurd_slab_dealloc (&_hurd_cap_obj_entry_space, entry); - return 0; - } - - /* Add the entry to the cap table of the client. */ - err = hurd_table_enter (&client->caps, &entry, &entry->id); - if (err) - { - pthread_mutex_unlock (&client->lock); - hurd_slab_dealloc (&_hurd_cap_obj_entry_space, entry); - return err; - } - err = hurd_ihash_add (&client->caps_reverse, - (hurd_ihash_key_t) obj, entry); - if (err) - { - hurd_table_remove (&client->caps, entry->id); - pthread_mutex_unlock (&client->lock); - hurd_slab_dealloc (&_hurd_cap_obj_entry_space, entry); - return err; - } - - *r_id = entry->id; - pthread_mutex_unlock (&client->lock); - - /* Add the object to the list. */ - _hurd_cap_list_item_add (&obj->clients, &entry->client_item); - - /* Add a reference for the internal reference of the capability - entry to the capability object. */ - obj->refs++; - - /* FIXME: Should probably use spin lock here, or so. */ - pthread_mutex_lock (&bucket->lock); - bucket->nr_caps++; - pthread_mutex_unlock (&bucket->lock); - - return 0; - } -} diff --git a/libhurd-cap-server/obj-dealloc.c b/libhurd-cap-server/obj-dealloc.c deleted file mode 100644 index de4421e..0000000 --- a/libhurd-cap-server/obj-dealloc.c +++ /dev/null @@ -1,50 +0,0 @@ -/* obj-dealloc.c - Deallocate a capability object. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <pthread.h> - -#include "cap-server-intern.h" - - -/* Deallocate the capability object OBJ, which must be locked and have - no more references. */ -void -_hurd_cap_obj_dealloc (hurd_cap_obj_t obj) -{ - hurd_cap_class_t cap_class = obj->cap_class; - - /* First let the user do their reinitialization. */ - (*cap_class->obj_reinit) (cap_class, obj); - - /* Now do our part of the reinitialization. */ - assert (obj->refs == 0); - assert (obj->state == _HURD_CAP_STATE_GREEN); - assert (obj->pending_rpcs == NULL); - assert (obj->clients == NULL); - hurd_cap_obj_unlock (obj); - - hurd_slab_dealloc (&cap_class->obj_space, obj); -} diff --git a/libhurd-cap-server/obj-drop.c b/libhurd-cap-server/obj-drop.c deleted file mode 100644 index 6942ab1..0000000 --- a/libhurd-cap-server/obj-drop.c +++ /dev/null @@ -1,36 +0,0 @@ -/* obj-drop.c - Drop a reference to a capability object. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include "cap-server-intern.h" - - -/* Remove one reference for the capability object OBJ, which must be - locked, and will be unlocked when the function returns. If this - was the last user of this object, the object is deallocated. */ -void -hurd_cap_obj_drop (hurd_cap_obj_t obj) -{ - _hurd_cap_obj_drop (obj); -} diff --git a/libhurd-cap-server/obj-entry-space.c b/libhurd-cap-server/obj-entry-space.c deleted file mode 100644 index 5eb33ba..0000000 --- a/libhurd-cap-server/obj-entry-space.c +++ /dev/null @@ -1,52 +0,0 @@ -/* obj-entry-space.c - The capability object entry slab space. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> - -#include <hurd/slab.h> - -#include "cap-server-intern.h" - - -static error_t -_hurd_cap_obj_entry_constructor (void *hook, void *buffer) -{ - _hurd_cap_obj_entry_t entry = (_hurd_cap_obj_entry_t) buffer; - - /* The members cap_obj and client_item are initialized at - instantiation time. */ - - entry->dead = 0; - entry->internal_refs = 1; - entry->external_refs = 1; - - return 0; -} - - -/* The global slab for all capability entries. */ -struct hurd_slab_space _hurd_cap_obj_entry_space - = HURD_SLAB_SPACE_INITIALIZER (struct _hurd_cap_obj_entry, NULL, NULL, - _hurd_cap_obj_entry_constructor, NULL, NULL); diff --git a/libhurd-cap-server/obj-inhibit.c b/libhurd-cap-server/obj-inhibit.c deleted file mode 100644 index 22455b3..0000000 --- a/libhurd-cap-server/obj-inhibit.c +++ /dev/null @@ -1,131 +0,0 @@ -/* obj-inhibit.c - Inhibit RPCs on a capability object. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "cap-server-intern.h" - - -/* Inhibit all RPCs on the capability object CAP_OBJ (which must not - be locked). You _must_ follow up with a hurd_cap_obj_resume - operation, and hold at least one reference to the object - continuously until you did so. */ -error_t -hurd_cap_obj_inhibit (hurd_cap_obj_t obj) -{ - hurd_cap_class_t cap_class = obj->cap_class; - error_t err; - - /* First take the class-wide lock for conditions on capability - object states. */ - pthread_mutex_lock (&cap_class->obj_cond_lock); - - /* Then lock the object to check its state. */ - pthread_mutex_lock (&obj->lock); - - /* First wait until any other inhibitor has resumed the capability - object. This ensures that capability object inhibitions are - fully serialized (per capability object). */ - while (obj->state != _HURD_CAP_STATE_GREEN) - { - pthread_mutex_unlock (&obj->lock); - err = hurd_cond_wait (&cap_class->obj_cond, - &cap_class->obj_cond_lock); - if (err) - { - /* We have been canceled. */ - pthread_mutex_unlock (&cap_class->obj_cond_lock); - return err; - } - pthread_mutex_lock (&obj->lock); - } - - /* Now it is our turn to inhibit the capability object. */ - obj->cond_waiter = pthread_self (); - - if (_hurd_cap_obj_cond_busy (obj)) - { - _hurd_cap_list_item_t pending_rpc = obj->pending_rpcs; - - /* There are still pending RPCs (beside us). Cancel them. */ - while (pending_rpc) - { - if (pending_rpc->thread != obj->cond_waiter) - pthread_cancel (pending_rpc->thread); - pending_rpc = pending_rpc->next; - } - - /* Indicate that we would like to know when they have gone. */ - obj->state = _HURD_CAP_STATE_YELLOW; - - /* The last one will shut the door. */ - do - { - pthread_mutex_unlock (&obj->lock); - err = hurd_cond_wait (&cap_class->obj_cond, - &cap_class->obj_cond_lock); - if (err) - { - /* We have been canceled ourselves. Give up. */ - obj->state = _HURD_CAP_STATE_GREEN; - pthread_mutex_unlock (&cap_class->obj_cond_lock); - return err; - } - pthread_mutex_lock (&obj->lock); - } - while (obj->state != _HURD_CAP_STATE_RED); - } - else - obj->state = _HURD_CAP_STATE_RED; - - /* Now all pending RPCs have been canceled and are completed (except - us), and all incoming RPCs are inhibited. */ - pthread_mutex_unlock (&obj->lock); - pthread_mutex_unlock (&cap_class->obj_cond_lock); - - return 0; -} - - -/* Resume RPCs on the capability object OBJ and wake-up all - waiters. */ -void -hurd_cap_obj_resume (hurd_cap_obj_t obj) -{ - hurd_cap_class_t cap_class = obj->cap_class; - - pthread_mutex_lock (&cap_class->obj_cond_lock); - pthread_mutex_lock (&obj->lock); - - obj->state = _HURD_CAP_STATE_GREEN; - - /* Broadcast the change to all potential waiters. */ - pthread_cond_broadcast (&cap_class->obj_cond); - - pthread_mutex_unlock (&obj->lock); - pthread_mutex_unlock (&cap_class->obj_cond_lock); -} diff --git a/libhurd-cap-server/table.c b/libhurd-cap-server/table.c deleted file mode 100644 index 8a0acd3..0000000 --- a/libhurd-cap-server/table.c +++ /dev/null @@ -1,96 +0,0 @@ -/* table.c - Table abstraction implementation. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <string.h> - -#include "table.h" - - -/* Initialize the table TABLE. */ -error_t -hurd_table_init (hurd_table_t table, unsigned int entry_size) -{ - assert (sizeof (entry_size) >= sizeof (void *)); - - *table = (struct hurd_table) HURD_TABLE_INITIALIZER (entry_size); - return 0; -} - - -/* Destroy the table TABLE. */ -void -hurd_table_destroy (hurd_table_t table) -{ - if (table->data) - free (table->data); -} - - -/* The initial table size. */ -#define TABLE_START_SIZE 4 - -/* Add the table element DATA to the table TABLE. The index for this - element is returned in R_IDX. Note that the data is added by - copying ENTRY_SIZE bytes into the table (the ENTRY_SIZE parameter - was provided at table initialization time). */ -error_t -hurd_table_enter (hurd_table_t table, void *data, unsigned int *r_idx) -{ - unsigned int idx; - - if (table->used == table->size) - { - unsigned int size_new = table->size ? 2 * table->size : TABLE_START_SIZE; - void *data_new; - - data_new = realloc (table->data, size_new * table->entry_size); - if (!data_new) - return errno; - - table->first_free = table->size; - table->data = data_new; - table->size = size_new; - } - - for (idx = table->first_free; idx < table->init_size; idx++) - if (_HURD_TABLE_ENTRY_LOOKUP (table, idx) == HURD_TABLE_EMPTY) - break; - - /* The following setting for FIRST_FREE is safe, because if this was - the last table entry, then the table is full and we will grow the - table the next time we are called (if no elements are removed in - the meantime. */ - table->first_free = idx + 1; - - if (idx == table->init_size) - table->init_size++; - - memcpy (HURD_TABLE_LOOKUP (table, idx), data, table->entry_size); - table->used++; - *r_idx = idx; - return 0; -} - diff --git a/libhurd-cap-server/table.h b/libhurd-cap-server/table.h deleted file mode 100644 index 4278466..0000000 --- a/libhurd-cap-server/table.h +++ /dev/null @@ -1,207 +0,0 @@ -/* table.h - Table abstraction interface. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _HURD_TABLE_H -#define _HURD_TABLE_H 1 - -#include <errno.h> -#include <stdlib.h> -#include <assert.h> - - -/* The hurd_table data type is a fancy array. At initialization time, - you have to provide the size ENTRY_SIZE of each table entry. When - you enter an element, you get an index number in return. This - index can be used for fast lookup of table elements. You access - the table elements through pointers to the beginning of the each - block of ENTRY_SIZE bytes. - - Embedded at the beginning of the ENTRY_SIZE bytes in each slot is a - void pointer. You can use this void pointer freely for your own - purpose with the following restriction: In a used table entry, it - must never be NULL. NULL at the beginning of a table entry - indicates an unused (free) table entry. - - The table will grow (and eventually shrink, not yet implemented) - automatically. New elements are always allocated from the - beginning of the table. This means that when a new element is - added, the free slot with the lowest index is always used. This - makes slot usage predictable and attempts to prevent fragmentation - and sparse usage. - - Note that tables, unlike hashes, can not be reorganized, because - the index is not stable under reorganization. - - Of all operations supported, only lookup is immediate. Entering - new elements is usually fast, too, unless the first free slot is - unknown and has to be searched for, or there are no more free slots - and the table has to be enlarged. - - Iterating over the used elements of the table is always - of the order of the table size. - - In the future, removing an element can also shrink the table. In - order to be able to do this, the implementation keeps track of the - last used slot. For this reason, the remove operation is sometimes - not immediate. */ - - -/* Because the first element in each table entry is a pointer, the - table entry should be naturally aligned. */ -#define _HURD_TABLE_ALIGN(x) \ - (((x) + sizeof (void *) - 1) & ~(sizeof (void *) - 1)) - - -/* The value used for empty table entries. */ -#define HURD_TABLE_EMPTY (NULL) - -struct hurd_table -{ - /* The size of one entry. Must at least be sizeof (void *). At the - beginning of each entry, a void * should be present that is - HURD_TABLE_EMPTY for unused elements and something else for used - table elements. */ - unsigned int entry_size; - - /* The number of allocated table entries. */ - unsigned int size; - - /* The number of table entries that are initialized. */ - unsigned int init_size; - - /* The number of used table entries. */ - unsigned int used; - - /* The index of the lowest entry that is unused. */ - unsigned int first_free; - - /* The index after the highest entry that is used. */ - unsigned int last_used; - - /* The table data. */ - char *data; -}; -typedef struct hurd_table *hurd_table_t; - - -#define HURD_TABLE_INITIALIZER(size_of_one) \ - { .entry_size = _HURD_TABLE_ALIGN (size_of_one), .size = 0, \ - .init_size = 0, .used = 0, .first_free = 0, .last_used = 0, \ - .data = NULL } - -/* Fast accessor without range check. */ -#define HURD_TABLE_LOOKUP(table, idx) \ - (&(table)->data[(idx) * (table)->entry_size]) - -/* This is an lvalue for the pointer embedded in the table entry. */ -#define _HURD_TABLE_ENTRY(entry) (*(void **) (entry)) - -#define _HURD_TABLE_ENTRY_LOOKUP(table, idx) \ - _HURD_TABLE_ENTRY (HURD_TABLE_LOOKUP (table, idx)) - - -/* Initialize the table TABLE. */ -error_t hurd_table_init (hurd_table_t table, unsigned int entry_size); - - -/* Destroy the table TABLE. */ -void hurd_table_destroy (hurd_table_t table); - - -/* Add the table element DATA to the table TABLE. The index for this - element is returned in R_IDX. Note that the data is added by - copying ENTRY_SIZE bytes into the table (the ENTRY_SIZE parameter - was provided at table initialization time). */ -error_t hurd_table_enter (hurd_table_t table, void *data, unsigned int *r_idx); - - -/* Lookup the table element with the index IDX in the table TABLE. If - there is no element with this index, return NULL. Otherwise a - pointer to the table entry is returned. */ -static inline void * -hurd_table_lookup (hurd_table_t table, unsigned int idx) -{ - void *result; - - if (idx >= table->init_size) - return NULL; - - result = HURD_TABLE_LOOKUP (table, idx); - if (_HURD_TABLE_ENTRY (result) == HURD_TABLE_EMPTY) - return NULL; - - return result; -} - - -/* Remove the table element with the index IDX from the table - TABLE. */ -static inline void -hurd_table_remove (hurd_table_t table, unsigned int idx) -{ - void *entry; - - assert (idx < table->init_size); - - entry = HURD_TABLE_LOOKUP (table, idx); - assert (_HURD_TABLE_ENTRY (entry) != HURD_TABLE_EMPTY); - - _HURD_TABLE_ENTRY (entry) = HURD_TABLE_EMPTY; - - if (idx < table->first_free) - table->first_free = idx; - - if (idx == table->last_used - 1) - while (--table->last_used > 0) - if (_HURD_TABLE_ENTRY_LOOKUP (table, table->last_used - 1) - == HURD_TABLE_EMPTY) - break; - - table->used--; -} - - -/* Iterate over all elements in the table. You use this macro - with a block, for example like this: - - error_t err; - HURD_TABLE_ITERATE (table, idx) - { - err = foo (idx); - if (err) - break; - } - if (err) - cleanup_and_return (); - - Or even like this: - - HURD_TABLE_ITERATE (ht, idx) - foo (idx); - - The block will be run for every used element in the table. Because - IDX is already a verified valid table index, you can lookup the - table entry with the fast macro HURD_TABLE_LOOKUP. */ -#define HURD_TABLE_ITERATE(table, idx) \ - for (unsigned int idx = 0; idx < (table)->init_size; idx++) \ - if (_HURD_TABLE_ENTRY_LOOKUP ((table), (idx)) != HURD_TABLE_EMPTY) - -#endif /* _HURD_TABLE_H */ diff --git a/libhurd-cap-server/task-death.c b/libhurd-cap-server/task-death.c deleted file mode 100644 index 855ed7a..0000000 --- a/libhurd-cap-server/task-death.c +++ /dev/null @@ -1,77 +0,0 @@ -/* task-death.c - Task death notifications, implementation. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <pthread.h> - -#include <hurd/types.h> -#include "task-death.h" - - -/* A lock that protects the linked list. It also is held when - callback handlers are called. */ -pthread_mutex_t hurd_task_death_notify_lock = PTHREAD_MUTEX_INITIALIZER; - -/* The linked list of callback handlers. */ -struct hurd_task_death_notify_list_item *hurd_task_death_notify_list; - - -static void * -task_death_manager (void *unused) -{ - /* FIXME. Needs to be implement when the task server supports - it. Do the following: - - unsigned int nr_task_ids; - unsigned int i; - hurd_task_id_t task_ids[nr_task_ids]; - - struct hurd_task_death_notify_list_item *item; - - pthread_mutex_lock (&hurd_task_death_notify_lock); - item = hurd_task_death_notify_list; - while (item) - { - for (i = 0; i < nr_task_ids; i++) - (*item->notify_handler) (item->hook, task_id[i]); - item = item->next; - } - pthread_mutex_unlock (&hurd_task_death_notify_lock); - - The only bit missing is the RPC loop to retrieve the dead task ids - from the task server. This can be a tight loop. */ - - return 0; -} - - -/* Start task death notifications. Must be called once at startup. */ -error_t -hurd_task_death_notify_start (void) -{ - /* FIXME. Needs to be implement when the task server supports it. - Start the task_death_manager thread. */ - - return 0; -} diff --git a/libhurd-cap-server/task-death.h b/libhurd-cap-server/task-death.h deleted file mode 100644 index c4b72a8..0000000 --- a/libhurd-cap-server/task-death.h +++ /dev/null @@ -1,123 +0,0 @@ -/* task-death.h - Task death notifications, interface. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann <marcus@gnu.org> - - This file is part of the GNU Hurd. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _HURD_TASK_DEATH_H -#define _HURD_TASK_DEATH_H 1 - -#include <pthread.h> - - -/* We need to keep track of task deaths, because for IPC security we - hold task info capabilities which block reuse of the respective - task ID. At task death, we have to release these task info - capabilities so they become free for reuse. The task server - provides an interface to get the task IDs of all dead tasks to - which we still hold task info capabilities. - - The following convention applies: Before you start allocating task - info capabilities, you must register a task death notify handler. - While you are requesting new task info capabilities and registering - it with your notify handler, you must take the - hurd_task_death_notify_lock to prevent task death notifications - from being processed (FIXME: Write a wrapper function for the task - server RPC to do this). You can release task info capabilities at - any time. However, if your notify handler is called, you MUST - release any task info capability you hold for that task ID. */ - - -/* The type of a function callback that you can use to be informed - about task deaths. */ -typedef void (task_death_notify_t) (void *hook, hurd_task_id_t task_id); - -/* The struct you have to use to add your own notification - handler. */ -struct hurd_task_death_notify_list_item -{ - /* The following two members are internal. */ - struct hurd_task_death_notify_list_item *next; - struct hurd_task_death_notify_list_item **prevp; - - /* Your callback handler. */ - task_death_notify_t *notify_handler; - - /* This is passed as the first argument to your callback - handler. */ - void *hook; -}; - - -/* A lock that protects the linked list. It also is held when - callback handlers are called. */ -extern pthread_mutex_t hurd_task_death_notify_lock; - -/* The linked list of callback handlers. */ -extern struct hurd_task_death_notify_list_item *hurd_task_death_notify_list; - - -/* Start task death notifications. Must be called once at startup. */ -error_t hurd_task_death_notify_start (void); - - -/* Add the callback handler ITEM to the list. */ -static inline void -hurd_task_death_notify_add (struct hurd_task_death_notify_list_item *item) -{ - pthread_mutex_lock (&hurd_task_death_notify_lock); - if (hurd_task_death_notify_list) - hurd_task_death_notify_list->prevp = &item->next; - item->prevp = &hurd_task_death_notify_list; - item->next = hurd_task_death_notify_list; - hurd_task_death_notify_list = item; - pthread_mutex_unlock (&hurd_task_death_notify_lock); -}; - - -/* Remove the callback handler ITEM from the list. */ -static inline void -hurd_task_death_notify_remove (struct hurd_task_death_notify_list_item *item) -{ - pthread_mutex_lock (&hurd_task_death_notify_lock); - if (item->next) - item->next->prevp = item->prevp; - *(item->prevp) = item->next; - pthread_mutex_unlock (&hurd_task_death_notify_lock); -}; - - -/* Suspend processing task death notifications. Call this while - acquiring new task info capabilities and registering them with your - notify handler. */ -static inline void -hurd_task_death_notify_suspend (void) -{ - pthread_mutex_lock (&hurd_task_death_notify_lock); -} - -/* Resumes processing task death notifications. Call this after - acquiring new task info capabilities and registering them with your - notify handler. */ -static inline void -hurd_task_death_notify_resume (void) -{ - pthread_mutex_unlock (&hurd_task_death_notify_lock); -} - -#endif /* _HURD_TASK_DEATH_H */ |