summaryrefslogtreecommitdiff
path: root/libhurd-cap-server/cap-server-intern.h
diff options
context:
space:
mode:
Diffstat (limited to 'libhurd-cap-server/cap-server-intern.h')
-rw-r--r--libhurd-cap-server/cap-server-intern.h225
1 files changed, 209 insertions, 16 deletions
diff --git a/libhurd-cap-server/cap-server-intern.h b/libhurd-cap-server/cap-server-intern.h
index c58067c..b9dd284 100644
--- a/libhurd-cap-server/cap-server-intern.h
+++ b/libhurd-cap-server/cap-server-intern.h
@@ -34,9 +34,6 @@
#define hurd_cond_wait pthread_cond_wait
-/* Forward declaration. */
-struct hurd_cap_client;
-
/* 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
@@ -51,23 +48,59 @@ struct _hurd_cap_list_item
struct
{
/* This location pointer is used for fast removal from the
- CAP_CLASS->client_thread hash. Unused for classes and
- capability objects. */
+ 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
{
- struct hurd_cap_client *client;
+ _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. */
@@ -104,7 +137,7 @@ struct _hurd_cap_obj_entry
hurd_cap_obj_t cap_obj;
/* The index in the capability table. */
- hurd_cap_id_t idx;
+ 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
@@ -137,6 +170,13 @@ typedef struct _hurd_cap_obj_entry *_hurd_cap_obj_entry_t;
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. */
@@ -188,7 +228,6 @@ struct _hurd_cap_client
/* Reverse lookup from hurd_cap_obj_t to _hurd_cap_obj_entry_t. */
struct hurd_ihash caps_reverse;
};
-typedef struct _hurd_cap_client *_hurd_cap_client_t;
/* The global slab space for all capability clients. */
@@ -201,13 +240,14 @@ extern struct hurd_slab_space _hurd_cap_client_space
found, create it. */
error_t _hurd_cap_client_create (hurd_cap_bucket_t bucket,
hurd_task_id_t task_id,
- hurd_cap_id_t *r_idx,
_hurd_cap_client_t *r_client)
__attribute__((visibility("hidden")));
/* Deallocate the connection client CLIENT. */
-void _hurd_cap_client_dealloc (_hurd_cap_client_t 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
@@ -218,22 +258,22 @@ void _hurd_cap_client_release (hurd_cap_bucket_t bucket,
/* Inhibit all RPCs on the capability client CLIENT (which must not be
- locked) in the capability class CAP_CLASS. 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. */
+ 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 class CAP_CLASS
+/* 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 class CAP_CLASS and
+/* 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)
@@ -307,18 +347,41 @@ struct _hurd_cap_bucket
/* 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 or filled (whatever it is not right now).
+ 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. */
+ /* 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 numbers to the list items in
PENDING_RPCs. This is used to limit each client thread to just
one RPC at one time. */
@@ -332,4 +395,134 @@ struct _hurd_cap_bucket
};
+/* 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->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 inhibition 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);
+ }
+}
+
+
#endif /* _HURD_CAP_SERVER_INTERN_H */