2 * Copyright (c) 2002 David Xu(davidxu@freebsd.org).
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Test Userland Thread Scheduler (UTS) suite for KSE.
31 * Test Userland round roubin.
34 #include <sys/types.h>
35 #include <sys/signal.h>
36 #include <sys/signalvar.h>
37 #include <sys/sysctl.h>
39 #include <sys/ucontext.h>
48 #include "simplelock.h"
53 #define UPFMT(fmt...) pfmt(#fmt)
54 #define UPSTR(s) pstr(s)
55 #define UPCHAR(c) pchar(c)
57 #define UPFMT(fmt...) /* Nothing. */
58 #define UPSTR(s) /* Nothing. */
59 #define UPCHAR(c) /* Nothing. */
62 #define MAIN_STACK_SIZE (1024 * 1024)
63 #define THREAD_STACK_SIZE (32 * 1024)
66 struct kse_thr_mailbox *head;
67 struct simplelock lock;
71 struct kse_mailbox mb;
72 struct uts_runq *runq;
73 struct kse_thr_mailbox *cur_thread;
76 static struct uts_runq runq1;
77 static struct uts_data data1;
79 static void init_uts(struct uts_data *data, struct uts_runq *q);
80 static void start_uts(struct uts_data *data, int newgrp);
81 static void enter_uts(struct uts_data *);
82 static void pchar(char c);
83 static void pfmt(const char *fmt, ...);
84 static void pstr(const char *s);
85 static void runq_init(struct uts_runq *q);
86 static void runq_insert(struct uts_runq *q, struct kse_thr_mailbox *tm);
87 static struct kse_thr_mailbox *runq_remove(struct uts_runq *q);
88 static struct kse_thr_mailbox *runq_remove_nolock(struct uts_runq *q);
89 static void thread_start(struct uts_data *data, const void *func, int arg);
90 static void uts(struct kse_mailbox *km);
92 /* Functions implemented in assembly */
93 extern int uts_to_thread(struct kse_thr_mailbox *tdp,
94 struct kse_thr_mailbox **curthreadp);
95 extern int thread_to_uts(struct kse_thr_mailbox *tm,
96 struct kse_mailbox *km);
110 init_uts(&data1, &runq1);
111 thread_start(&data1, deadloop, 0);
112 thread_start(&data1, deadloop, 0);
113 thread_start(&data1, deadloop, 0);
114 start_uts(&data1, 0);
116 pstr("\n** main() exiting **\n");
122 * Enter the UTS from a thread.
125 enter_uts(struct uts_data *data)
127 struct kse_thr_mailbox *td;
129 /* XXX: We should atomically exchange these two. */
130 td = data->mb.km_curthread;
131 data->mb.km_curthread = NULL;
133 thread_to_uts(td, &data->mb);
137 * Initialise threading.
140 init_uts(struct uts_data *data, struct uts_runq *q)
142 struct kse_thr_mailbox *tm;
150 * Create initial thread.
152 tm = (struct kse_thr_mailbox *)calloc(1, sizeof(struct kse_thr_mailbox));
154 /* Throw us into its context. */
155 getcontext(&tm->tm_context);
157 /* Find our stack. */
159 mib[1] = KERN_USRSTACK;
162 if (sysctl(mib, 2, &p, &len, NULL, 0) == -1)
163 pstr("sysctl(CTL_KER.KERN_USRSTACK) failed.\n");
165 p = (char *)malloc(MAIN_STACK_SIZE) + MAIN_STACK_SIZE;
166 pfmt("main() : 0x%x\n", tm);
167 pfmt("eip -> 0x%x\n", tm->tm_context.uc_mcontext.mc_eip);
168 tm->tm_context.uc_stack.ss_sp = p - MAIN_STACK_SIZE;
169 tm->tm_context.uc_stack.ss_size = MAIN_STACK_SIZE;
172 * Create KSE mailbox.
174 p = (char *)malloc(THREAD_STACK_SIZE);
175 bzero(&data->mb, sizeof(struct kse_mailbox));
176 data->mb.km_stack.ss_sp = p;
177 data->mb.km_stack.ss_size = THREAD_STACK_SIZE;
178 data->mb.km_func = (void *)uts;
179 data->mb.km_udata = data;
180 data->mb.km_quantum = 10000;
181 data->cur_thread = tm;
183 pfmt("uts() at : 0x%x\n", uts);
184 pfmt("uts stack at : 0x%x - 0x%x\n", p, p + THREAD_STACK_SIZE);
188 start_uts(struct uts_data *data, int newgrp)
191 * Start KSE scheduling.
193 pfmt("kse_create() -> %d\n", kse_create(&data->mb, newgrp));
194 data->mb.km_curthread = data->cur_thread;
198 * Write a single character to stdout, in a thread-safe manner.
204 write(STDOUT_FILENO, &c, 1);
208 * Write formatted output to stdout, in a thread-safe manner.
210 * Recognises the following conversions:
212 * %d -> signed int (base 10)
214 * %u -> unsigned int (base 10)
215 * %x -> unsigned int (base 16)
218 pfmt(const char *fmt, ...)
220 static const char digits[16] = "0123456789abcdef";
228 while ((c = *fmt++)) {
233 pchar(va_arg(ap, int));
236 pstr(va_arg(ap, char *));
241 r = ((c == 'u') || (c == 'd')) ? 10 : 16;
243 d = va_arg(ap, unsigned);
246 u = (unsigned)(d * -1);
250 u = va_arg(ap, unsigned);
253 *s++ = digits[u % r];
269 write(STDOUT_FILENO, s, strlen(s));
273 runq_init(struct uts_runq *q)
276 simplelock_init(&q->lock);
280 * Insert a thread into the run queue.
283 runq_insert(struct uts_runq *q, struct kse_thr_mailbox *tm)
285 simplelock_lock(&q->lock);
286 tm->tm_next = q->head;
288 simplelock_unlock(&q->lock);
292 * Select and remove a thread from the run queue.
294 static struct kse_thr_mailbox *
295 runq_remove(struct uts_runq *q)
297 struct kse_thr_mailbox *tm;
299 simplelock_lock(&q->lock);
300 tm = runq_remove_nolock(q);
301 simplelock_unlock(&q->lock);
305 static struct kse_thr_mailbox *
306 runq_remove_nolock(struct uts_runq *q)
308 struct kse_thr_mailbox *p, *p1;
313 for (p = q->head; p->tm_next != NULL; p = p->tm_next)
323 * Userland thread scheduler.
326 uts(struct kse_mailbox *km)
328 struct kse_thr_mailbox *tm, *p;
329 struct uts_data *data;
331 UPSTR("\n--uts() start--\n");
332 UPFMT("mailbox -> %x\n", km);
335 * Insert any processes back from being blocked
336 * in the kernel into the run queue.
339 p = km->km_completed;
340 km->km_completed = NULL;
341 UPFMT("km_completed -> 0x%x", p);
342 while ((tm = p) != NULL) {
345 runq_insert(data->runq, tm);
350 * Pull a thread off the run queue.
352 simplelock_lock(&data->runq->lock);
353 p = runq_remove_nolock(data->runq);
354 simplelock_unlock(&data->runq->lock);
357 * Either schedule a thread, or idle if none ready to run.
360 UPFMT("\n-- uts() scheduling 0x%x--\n", p);
361 UPFMT("eip -> 0x%x progress -> %d\n",
362 p->tm_context.uc_mcontext.mc_eip, progress);
363 UPSTR("curthread set\n");
365 uts_to_thread(p, &km->km_curthread);
366 UPSTR("\n-- uts_to_thread() failed --\n");
369 pstr("** uts() exiting **\n");
376 static struct kse_thr_mailbox *
377 thread_create(const void *func, int arg)
379 struct kse_thr_mailbox *tm;
382 tm = (struct kse_thr_mailbox *)calloc(1, sizeof(struct kse_thr_mailbox));
383 getcontext(&tm->tm_context);
384 p = (char *)malloc(THREAD_STACK_SIZE);
385 tm->tm_context.uc_stack.ss_sp = p;
386 tm->tm_context.uc_stack.ss_size = THREAD_STACK_SIZE;
387 makecontext(&tm->tm_context, func, 1, arg);
388 // setcontext(&tm->tm_context);
393 thread_start(struct uts_data *data, const void *func, int arg)
395 struct kse_thr_mailbox *tm;
396 struct kse_thr_mailbox *tm2;
398 tm = thread_create(func, arg);
399 tm2 = thread_create(enter_uts, (int)data);
400 tm->tm_context.uc_link = &tm2->tm_context;
401 runq_insert(data->runq, tm);
402 pfmt("thread_start() : 0x%x\n", tm);