summaryrefslogtreecommitdiff
path: root/task/task-id.c
diff options
context:
space:
mode:
Diffstat (limited to 'task/task-id.c')
-rw-r--r--task/task-id.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/task/task-id.c b/task/task-id.c
new file mode 100644
index 0000000..ec51d05
--- /dev/null
+++ b/task/task-id.c
@@ -0,0 +1,121 @@
+/* task-id.c - Manage task IDs.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+
+#include "task.h"
+
+
+/* The hash table mapping task IDs to tasks. */
+struct hurd_ihash task_id_to_task
+ = HURD_IHASH_INITIALIZER (offsetof (struct task, locp));
+
+/* The lock protecting the task_it_to_task hash table and associated
+ data. */
+pthread_mutex_t task_id_to_task_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define task_id_is_free(task_id) \
+ (hurd_ihash_find (&task_id_to_task, (task_id)) == NULL)
+
+
+/* Enter the task TASK under its ID into the hash table, consuming one
+ reference. Mainly used by the bootstrap functions. */
+error_t
+task_id_enter (task_t task)
+{
+ error_t err;
+
+ pthread_mutex_lock (&task_id_to_task_lock);
+ err = hurd_ihash_add (&task_id_to_task, task->task_id, task);
+ pthread_mutex_unlock (&task_id_to_task_lock);
+
+ return err;
+}
+
+
+/* Increment the task_id_next marker. */
+static inline hurd_task_id_t
+task_id_inc (hurd_task_id_t task_id)
+{
+ /* We know that either the next task ID or the one after it is
+ valid. So we manually unroll the loop here. */
+
+ task_id++;
+ if (! L4_THREAD_VERSION_VALID (task_id))
+ task_id++;
+
+ return task_id;
+}
+
+
+/* Find a free task ID, enter the task TASK into the hash table under
+ this ID, consuming one reference, and return the new task ID. If
+ no free task ID is available, EAGAIN is returned. */
+error_t
+task_id_add (task_t task, hurd_task_id_t *task_id_p)
+{
+ /* Zero is an invalid task ID. But last_task_id will be incremented
+ to the next valid task ID before the first allocation takes
+ place. This variable is protected by task_id_to_task_lock. */
+ static hurd_task_id_t last_task_id;
+ error_t err = 0;
+ hurd_task_id_t task_id;
+
+ pthread_mutex_lock (&task_id_to_task_lock);
+
+ /* Find next valid task ID. */
+ task_id = task_id_inc (last_task_id);
+
+ if (__builtin_expect (! task_id_is_free (task_id), 0))
+ {
+ /* Slow path. The next task ID is taken. Skip forward until we
+ find a free one. */
+
+ /* The first task ID we tried. */
+ hurd_task_id_t first_task_id = task_id;
+
+ do
+ task_id = task_id_inc (task_id);
+ while (task_id != first_task_id && !task_id_is_free (task_id));
+
+ /* Check if we wrapped over and ended up where we started. */
+ if (task_id == first_task_id)
+ err = EAGAIN;
+ }
+
+ if (__builtin_expect (!err, 1))
+ {
+ err = hurd_ihash_add (&task_id_to_task, task_id, task);
+ if (__builtin_expect (!err, 1))
+ {
+ task->task_id = task_id;
+ *task_id_p = task_id;
+ last_task_id = task_id;
+ }
+ }
+
+ pthread_mutex_unlock (&task_id_to_task_lock);
+
+ return err;
+}