source: mainline/libc/generic/psthread.c@ 6c46350

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6c46350 was 01ff41c, checked in by Ondrej Palkovsky <ondrap@…>, 19 years ago

Added functions to async framework for reasonable sending asynchronous
messages.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * Copyright (C) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <libadt/list.h>
30#include <psthread.h>
31#include <malloc.h>
32#include <unistd.h>
33#include <thread.h>
34#include <stdio.h>
35#include <kernel/arch/faddr.h>
36#include <futex.h>
37#include <assert.h>
38#include <async.h>
39
40#ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
41#define PSTHREAD_INITIAL_STACK_PAGES_NO 1
42#endif
43
44static LIST_INITIALIZE(ready_list);
45static LIST_INITIALIZE(manager_list);
46
47static void psthread_exit(void) __attribute__ ((noinline));
48static void psthread_main(void);
49
50static atomic_t psthread_futex = FUTEX_INITIALIZER;
51
52/** Setup PSthread information into TCB structure */
53psthread_data_t * psthread_setup()
54{
55 psthread_data_t *pt;
56 tcb_t *tcb;
57
58 tcb = __make_tls();
59 if (!tcb)
60 return NULL;
61
62 pt = malloc(sizeof(*pt));
63 if (!pt) {
64 __free_tls(tcb);
65 return NULL;
66 }
67
68 tcb->pst_data = pt;
69 pt->tcb = tcb;
70
71 return pt;
72}
73
74void psthread_teardown(psthread_data_t *pt)
75{
76 __free_tls(pt->tcb);
77 free(pt);
78}
79
80/** Function to preempt to other pseudo thread without adding
81 * currently running pseudo thread to ready_list.
82 */
83void psthread_exit(void)
84{
85 psthread_data_t *pt;
86
87 futex_down(&psthread_futex);
88
89 if (!list_empty(&ready_list))
90 pt = list_get_instance(ready_list.next, psthread_data_t, link);
91 else if (!list_empty(&manager_list))
92 pt = list_get_instance(manager_list.next, psthread_data_t, link);
93 else {
94 printf("Cannot find suitable psthread to run.\n");
95 _exit(0);
96 }
97 list_remove(&pt->link);
98 futex_up(&psthread_futex);
99
100 context_restore(&pt->ctx);
101 /* Never reached */
102}
103
104/** Function that is called on entry to new uspace thread */
105void psthread_main(void)
106{
107 psthread_data_t *pt = __tcb_get()->pst_data;
108
109 pt->retval = pt->func(pt->arg);
110
111 pt->finished = 1;
112 if (pt->waiter)
113 list_append(&pt->waiter->link, &ready_list);
114
115 psthread_exit();
116}
117
118/** Schedule next userspace pseudo thread.
119 *
120 * If calling with PS_TO_MANAGER parameter, the async_futex should be
121 * held.
122 *
123 * @param tomanager If true, we are switching to next ready manager thread
124 * (if none is found, thread is exited)
125 * @param frommanager If true, we are switching from manager thread
126 * @return 0 if there is no ready pseudo thread, 1 otherwise.
127 */
128int psthread_schedule_next_adv(pschange_type ctype)
129{
130 psthread_data_t *pt;
131 int retval = 0;
132
133 futex_down(&psthread_futex);
134
135 if (ctype == PS_PREEMPT && list_empty(&ready_list))
136 goto ret_0;
137
138 if (ctype == PS_FROM_MANAGER && list_empty(&ready_list)) {
139 goto ret_0;
140 }
141 /* If we are going to manager and none exists, create it */
142 while (ctype == PS_TO_MANAGER && list_empty(&manager_list)) {
143 futex_up(&psthread_futex);
144 async_create_manager();
145 futex_down(&psthread_futex);
146 }
147
148 pt = __tcb_get()->pst_data;
149 if (!context_save(&pt->ctx))
150 return 1; // futex_up already done here
151
152 if (ctype == PS_PREEMPT)
153 list_append(&pt->link, &ready_list);
154 else if (ctype == PS_FROM_MANAGER)
155 list_append(&pt->link, &manager_list);
156
157 if (ctype == PS_TO_MANAGER)
158 pt = list_get_instance(manager_list.next,psthread_data_t, link);
159 else
160 pt = list_get_instance(ready_list.next, psthread_data_t, link);
161 list_remove(&pt->link);
162
163 futex_up(&psthread_futex);
164 context_restore(&pt->ctx);
165
166ret_0:
167 futex_up(&psthread_futex);
168 return retval;
169}
170
171/** Wait for uspace pseudo thread to finish.
172 *
173 * @param psthrid Pseudo thread to wait for.
174 *
175 * @return Value returned by the finished thread.
176 */
177int psthread_join(pstid_t psthrid)
178{
179 volatile psthread_data_t *pt, *mypt;
180 volatile int retval;
181
182 /* Handle psthrid = Kernel address -> it is wait for call */
183 pt = (psthread_data_t *) psthrid;
184
185 if (!pt->finished) {
186 mypt = __tcb_get()->pst_data;
187 if (context_save(&((psthread_data_t *) mypt)->ctx)) {
188 pt->waiter = (psthread_data_t *) mypt;
189 psthread_exit();
190 }
191 }
192 retval = pt->retval;
193
194 free(pt->stack);
195 psthread_teardown((void *)pt);
196
197 return retval;
198}
199
200/**
201 * Create a userspace thread
202 *
203 * @param func Pseudo thread function.
204 * @param arg Argument to pass to func.
205 *
206 * @return 0 on failure, TLS of the new pseudo thread.
207 */
208pstid_t psthread_create(int (*func)(void *), void *arg)
209{
210 psthread_data_t *pt;
211
212 pt = psthread_setup();
213 if (!pt)
214 return 0;
215 pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
216
217 if (!pt->stack) {
218 psthread_teardown(pt);
219 return 0;
220 }
221
222 pt->arg= arg;
223 pt->func = func;
224 pt->finished = 0;
225 pt->waiter = NULL;
226
227 context_save(&pt->ctx);
228 context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(),
229 pt->tcb);
230
231 return (pstid_t )pt;
232}
233
234/** Add a thread to ready list */
235void psthread_add_ready(pstid_t psthrid)
236{
237 psthread_data_t *pt;
238
239 pt = (psthread_data_t *) psthrid;
240 futex_down(&psthread_futex);
241 list_append(&pt->link, &ready_list);
242 futex_up(&psthread_futex);
243}
244
245/** Add a thread to manager list */
246void psthread_add_manager(pstid_t psthrid)
247{
248 psthread_data_t *pt;
249
250 pt = (psthread_data_t *) psthrid;
251
252 futex_down(&psthread_futex);
253 list_append(&pt->link, &manager_list);
254 futex_up(&psthread_futex);
255}
256
257/** Remove one manager from manager list */
258void psthread_remove_manager()
259{
260 futex_down(&psthread_futex);
261 if (list_empty(&manager_list)) {
262 futex_up(&psthread_futex);
263 return;
264 }
265 list_remove(manager_list.next);
266 futex_up(&psthread_futex);
267}
268
269/** Return thread id of current running thread */
270pstid_t psthread_get_id(void)
271{
272 return (pstid_t)__tcb_get()->pst_data;
273}
Note: See TracBrowser for help on using the repository browser.