diff options
Diffstat (limited to 'libhurd-cap-server/cap-server-intern.h')
-rw-r--r-- | libhurd-cap-server/cap-server-intern.h | 599 |
1 files changed, 0 insertions, 599 deletions
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 */ |