summaryrefslogtreecommitdiff
path: root/sos-code-article6.5/sos/thread.h
blob: 02ea83336ba9519feba4159da9821f7b6d4b1663 (plain) (blame)
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/* Copyright (C) 2004,2005 David Decotigny

   This program 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
   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 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-1307,
   USA. 
*/
#ifndef _SOS_THREAD_H_
#define _SOS_THREAD_H_

/**
 * @file thread.h
 *
 * SOS Thread management API
 */

#include <sos/errno.h>

/* Forward declaration */
struct sos_thread;

#include <hwcore/cpu_context.h>
#include <sos/sched.h>
#include <sos/kwaitq.h>
#include <sos/time.h>

/**
 * The possible states of a valid thread
 */
typedef enum { SOS_THR_CREATED, /**< Thread created, not fully initialized */
	       SOS_THR_READY,   /**< Thread fully initialized or
				     waiting for CPU after having been
				     blocked or preempted */
	       SOS_THR_RUNNING, /**< Thread currently running on CPU */
	       SOS_THR_BLOCKED, /**< Thread waiting for I/O (+ in at LEAST
				     one kwaitq) and/or sleeping (+ in NO
				     kwaitq) */
	       SOS_THR_ZOMBIE,  /**< Thread terminated execution, waiting to
				     be deleted by kernel */
             } sos_thread_state_t;


/**
 * TCB (Thread Control Block): structure describing a thread. Don't
 * access these fields directly: prefer using the accessor functions
 * below.
 */
struct sos_thread
{
#define SOS_THR_MAX_NAMELEN 32
  char name[SOS_THR_MAX_NAMELEN];

  sos_thread_state_t  state;

  /**
   * The hardware context of the thread.
   *
   * It will reflect the CPU state of the thread:
   *  - From an interrupt handler: the state of the thread at the time
   *    of the OUTERMOST irq. An IRQ is not allowed to make context
   *    switches, so this context will remain valid from the begining of
   *    the outermost IRQ handler to the end of it, no matter if there
   *    are other IRQ handlers nesting in one another. You may safely
   *    use it from IRQ handlers to query the state of the interrupted
   *    thread, no matter if there has been other IRQ handlers
   *    executing meanwhile.
   *  - From normal kernel code, exceptions and syscall: the state of
   *    the thread the last time there was a context switch from this
   *    thread to another one. Thus this field WON'T reflect the
   *    current's thread cpu_state in these cases. So, in these cases,
   *    simply DO NOT USE IT outside thread.c ! Note: for syscall and
   *    exception handlers, the VALID state of the interrupted thread is
   *    passed as an argument to the handlers.
   */
  struct sos_cpu_state *cpu_state;

  /* Kernel stack parameters */
  sos_vaddr_t kernel_stack_base_addr;
  sos_size_t  kernel_stack_size;

  /* Data specific to each state */
  union
  {
    struct
    {
      struct sos_thread     *rdy_prev, *rdy_next;
    } ready;
  }; /* Anonymous union (gcc extenion) */


  /*
   * Data used by the kwaitq subsystem: list of kwaitqueues the thread
   * is waiting for.
   *
   * @note: a RUNNING or READY thread might be in one or more
   * waitqueues ! The only property we have is that, among these
   * waitqueues (if any), _at least_ one has woken the thread.
   */
  struct sos_kwaitq_entry *kwaitq_list;


  /**
   * Chaining pointers for global ("gbl") list of threads (debug)
   */
  struct sos_thread *gbl_prev, *gbl_next;
};


/**
 * Definition of the function executed by a kernel thread
 */
typedef void (*sos_kernel_thread_start_routine_t)(void *arg);


/**
 * Initialize the subsystem responsible for thread management
 *
 * Initialize the primary kernel thread so that it can be handled the
 * same way as an ordinary thread created by sos_thread_create().
 */
sos_ret_t sos_thread_subsystem_setup(sos_vaddr_t init_thread_stack_base_addr,
				     sos_size_t init_thread_stack_size);


/**
 * Create a new kernel thread
 */
struct sos_thread *
sos_create_kernel_thread(const char *name,
			 sos_kernel_thread_start_routine_t start_func,
			 void *start_arg);


/**
 * Terminate the execution of the current thread. For kernel threads,
 * it is called by default when the start routine returns.
 */
void sos_thread_exit() __attribute__((noreturn));


/**
 * Get the identifier of the thread currently running on CPU. Trivial
 * function.
 */
struct sos_thread *sos_thread_get_current();


/**
 * If thr == NULL, get the state of the current thread. Trivial
 * function.
 *
 * @note NOT protected against interrupts
 */
sos_thread_state_t sos_thread_get_state(struct sos_thread *thr);


/**
 * Yield CPU to another ready thread.
 *
 * @note This is a BLOCKING FUNCTION
 */
sos_ret_t sos_thread_yield();


/**
 * Release the CPU for (at least) the given delay.
 *
 * @param delay The delay to wait for. If delay == NULL then wait
 * forever that any event occurs.
 *
 * @return SOS_OK when delay expired (and delay is reset to zero),
 * -SOS_EINTR otherwise (and delay contains the amount of time
 * remaining).
 *
 * @note This is a BLOCKING FUNCTION
 */
sos_ret_t sos_thread_sleep(/* in/out */struct sos_time *delay);


/**
 * Mark the given thread as READY (if not already ready) even if it is
 * blocked in a kwaitq or in a sleep ! As a result, the interrupted
 * kwaitq/sleep function call of the thread will return with
 * -SOS_EINTR.
 *
 * @return -SOS_EINVAL if thread does not exist, or -SOS_EFATAL if
 * marked ZOMBIE.
 *
 * @note As a result, the semaphore/mutex/conditions/... functions
 * return values SHOULD ALWAYS be checked ! If they are != SOS_OK,
 * then the caller should consider that the resource is not aquired
 * because somebody woke the thread by some way.
 */
sos_ret_t sos_thread_force_unblock(struct sos_thread *thread);


#endif /* _SOS_THREAD_H_ */