summaryrefslogtreecommitdiff
path: root/task/thread.c
blob: b2b4e0ef55fb315c4a52df82f94636695f021788 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* thread.c - Manage threads.
   Copyright (C) 2004, 2005 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 <assert.h>

#include <l4.h>

#include <hurd/slab.h>

#include "task.h"


/* Initialize the slab object pointed to by BUFFER.  HOOK is as
   provided to hurd_slab_create.  */
static error_t
thread_constructor (void *hook, void *buffer)
{
  thread_t thread = (thread_t) buffer;

  thread->next = NULL;
  thread->thread_id = l4_nilthread;

  return 0;
}


/* The slab space containing all thread objects.  As this is the only
   place where we keep track of used and free thread IDs, it must
   never be reaped (so no destructor is needed).  */
static struct hurd_slab_space threads
  = HURD_SLAB_SPACE_INITIALIZER (struct thread, NULL, NULL,
				 thread_constructor, NULL, NULL);

/* The lock protecting the threads slab.  */
static pthread_mutex_t threads_lock = PTHREAD_MUTEX_INITIALIZER;


/* The thread numbers are allocated sequentially starting from a first
   number and ending at a maximum number, which are set by
   thread_set_range.  */
static l4_thread_id_t next_thread_id = l4_nilthread;
static l4_thread_id_t last_thread_id;


/* Set the range of thread IDs that we are allowed to allocate.  */
void
thread_set_range (l4_thread_id_t first, l4_thread_id_t last)
{
  pthread_mutex_lock (&threads_lock);
  next_thread_id = first;
  last_thread_id = last;  
  pthread_mutex_unlock (&threads_lock);
}



/* Allocate a new thread object with the thread ID THREAD_ID and
   return it in THREAD.  Only used at bootstrap.  */
error_t
thread_alloc_with_id (l4_thread_id_t thread_id, thread_t *r_thread)
{
  error_t err;
  thread_t thread;
  union
  {
    void *buffer;
    thread_t thread;
  } u;

  pthread_mutex_lock (&threads_lock);
  err = hurd_slab_alloc (&threads, &u.buffer);
  thread = u.thread;
  if (!err)
    {
      assert (thread->thread_id == l4_nilthread);

      thread->thread_id = thread_id;
    }
  pthread_mutex_unlock (&threads_lock);

  *r_thread = thread;
  return err;
}


/* Allocate a new thread object and return it in THREAD.  */
error_t
thread_alloc (thread_t *r_thread)
{
  error_t err;
  thread_t thread;
  union
  {
    void *buffer;
    thread_t thread;
  } u;

  pthread_mutex_lock (&threads_lock);
  err = hurd_slab_alloc (&threads, &u.buffer);
  thread = u.thread;
  if (__builtin_expect (!err, 1))
    {
      if (__builtin_expect (thread->thread_id == l4_nilthread, 0))
	{
	  if (__builtin_expect (next_thread_id == l4_nilthread, 0))
	    err = EAGAIN;
	  else
	    {
	      thread->thread_id = next_thread_id;

	      if (__builtin_expect (next_thread_id == last_thread_id, 0))
		next_thread_id = l4_nilthread;
	      else
		/* The version number is arbitrary here.  */
		next_thread_id
		  = l4_global_id (l4_thread_no (next_thread_id) + 1, 1);
	    }
	}
    }
  pthread_mutex_unlock (&threads_lock);

  *r_thread = thread;
  return err;
}


/* Deallocate the thread THREAD.  */
void
thread_dealloc (thread_t thread)
{
  pthread_mutex_lock (&threads_lock);
  hurd_slab_dealloc (&  threads, thread);
  pthread_mutex_unlock (&threads_lock);
}