2 * Copyright (c) 2002 Jonathan Mini (mini@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
29 #include <sys/types.h>
30 #include <sys/signal.h>
31 #include <sys/signalvar.h>
32 #include <sys/sysctl.h>
34 #include <sys/ucontext.h>
43 #include "simplelock.h"
49 #define UPFMT(fmt...) pfmt(#fmt)
50 #define UPSTR(s) pstr(s)
51 #define UPCHAR(c) pchar(c)
53 #define UPFMT(fmt...) /* Nothing. */
54 #define UPSTR(s) /* Nothing. */
55 #define UPCHAR(c) /* Nothing. */
58 #define MAIN_STACK_SIZE (1024 * 1024)
59 #define THREAD_STACK_SIZE (32 * 1024)
62 struct kse_thr_mailbox *head;
63 struct simplelock lock;
67 struct kse_mailbox mb;
68 struct uts_runq *runq;
69 struct kse_thr_mailbox *cur_thread;
72 static struct uts_runq runq1;
73 static struct uts_data data1, data2;
74 static struct uts_runq runq2;
75 static struct uts_data data3, data4;
76 static struct kse_thr_mailbox *aa;
79 static int progress = 0;
82 static void init_uts(struct uts_data *data, struct uts_runq *q);
83 static void start_uts(struct uts_data *data, int newgrp);
84 static void enter_uts(struct uts_data *);
85 static void pchar(char c);
86 static void pfmt(const char *fmt, ...);
87 static void pstr(const char *s);
88 static void runq_init(struct uts_runq *q);
89 static void runq_insert(struct uts_runq *q, struct kse_thr_mailbox *tm);
90 static struct kse_thr_mailbox *runq_remove(struct uts_runq *q);
91 static struct kse_thr_mailbox *runq_remove_nolock(struct uts_runq *q);
92 static void thread_start(struct uts_data *data, const void *func, int arg);
93 static void uts(struct kse_mailbox *km);
95 /* Functions implemented in assembly */
96 extern int uts_to_thread(struct kse_thr_mailbox *tdp,
97 struct kse_thr_mailbox **curthreadp);
98 extern int thread_to_uts(struct kse_thr_mailbox *tm,
99 struct kse_mailbox *km);
104 struct timespec time_to_sleep;
105 struct timespec time_remaining;
107 time_to_sleep.tv_sec = 0;
108 time_to_sleep.tv_nsec = len * 10000;
109 nanosleep(&time_to_sleep, &time_remaining);
124 pfmt("\n[%d]\n", sig);
125 // thread_start(aaaa, '0' + progress++);
131 start_uts(&data4, 0);
138 for (;;) enter_uts(); sched_yield();
142 * Test Userland Thread Scheduler (UTS) suite for KSE.
150 init_uts(&data1, &runq1);
151 init_uts(&data2, &runq1);
152 thread_start(&data1, aaaa, '+');
153 thread_start(&data1, aaaa, '-');
154 start_uts(&data1, 0);
155 start_uts(&data2, 0);
157 // start second ksegrp
159 init_uts(&data3, &runq2);
160 init_uts(&data4, &runq2);
161 thread_start(&data3, newkse, 0);
162 thread_start(&data3, aaaa, '*');
163 thread_start(&data3, aaaa, '.');
164 start_uts(&data3, 1);
168 // thread_start(aaaa, 'a' + (i % 26));
169 pchar('A' + (i % 26));
172 pstr("\n** main() exiting **\n");
178 * Enter the UTS from a thread.
181 enter_uts(struct uts_data *data)
183 struct kse_thr_mailbox *td;
185 /* XXX: We should atomically exchange these two. */
186 td = data->mb.km_curthread;
187 data->mb.km_curthread = NULL;
189 thread_to_uts(td, &data->mb);
193 * Initialise threading.
196 init_uts(struct uts_data *data, struct uts_runq *q)
198 struct kse_thr_mailbox *tm;
206 * Create initial thread.
208 tm = (struct kse_thr_mailbox *)calloc(1, sizeof(struct kse_thr_mailbox));
210 /* Throw us into its context. */
211 getcontext(&tm->tm_context);
213 /* Find our stack. */
215 mib[1] = KERN_USRSTACK;
218 if (sysctl(mib, 2, &p, &len, NULL, 0) == -1)
219 pstr("sysctl(CTL_KER.KERN_USRSTACK) failed.\n");
221 p = (char *)malloc(MAIN_STACK_SIZE) + MAIN_STACK_SIZE;
222 pfmt("main() : 0x%x\n", tm);
223 pfmt("eip -> 0x%x\n", tm->tm_context.uc_mcontext.mc_eip);
224 tm->tm_context.uc_stack.ss_sp = p - MAIN_STACK_SIZE;
225 tm->tm_context.uc_stack.ss_size = MAIN_STACK_SIZE;
228 * Create KSE mailbox.
230 p = (char *)malloc(THREAD_STACK_SIZE);
231 bzero(&data->mb, sizeof(struct kse_mailbox));
232 data->mb.km_stack.ss_sp = p;
233 data->mb.km_stack.ss_size = THREAD_STACK_SIZE;
234 data->mb.km_func = (void *)uts;
235 data->mb.km_udata = data;
236 data->cur_thread = tm;
238 pfmt("uts() at : 0x%x\n", uts);
239 pfmt("uts stack at : 0x%x - 0x%x\n", p, p + THREAD_STACK_SIZE);
243 start_uts(struct uts_data *data, int newgrp)
246 * Start KSE scheduling.
248 pfmt("kse_create() -> %d\n", kse_create(&data->mb, newgrp));
249 data->mb.km_curthread = data->cur_thread;
252 * Arrange to deliver signals via KSE.
254 signal(SIGURG, foof);
258 * Write a single character to stdout, in a thread-safe manner.
264 write(STDOUT_FILENO, &c, 1);
268 * Write formatted output to stdout, in a thread-safe manner.
270 * Recognises the following conversions:
272 * %d -> signed int (base 10)
274 * %u -> unsigned int (base 10)
275 * %x -> unsigned int (base 16)
278 pfmt(const char *fmt, ...)
280 static const char digits[16] = "0123456789abcdef";
288 while ((c = *fmt++)) {
293 pchar(va_arg(ap, int));
296 pstr(va_arg(ap, char *));
301 r = ((c == 'u') || (c == 'd')) ? 10 : 16;
303 d = va_arg(ap, unsigned);
306 u = (unsigned)(d * -1);
310 u = va_arg(ap, unsigned);
313 *s++ = digits[u % r];
329 write(STDOUT_FILENO, s, strlen(s));
333 runq_init(struct uts_runq *q)
336 simplelock_init(&q->lock);
340 * Insert a thread into the run queue.
343 runq_insert(struct uts_runq *q, struct kse_thr_mailbox *tm)
345 simplelock_lock(&q->lock);
346 tm->tm_next = q->head;
348 simplelock_unlock(&q->lock);
352 * Select and remove a thread from the run queue.
354 static struct kse_thr_mailbox *
355 runq_remove(struct uts_runq *q)
357 struct kse_thr_mailbox *tm;
359 simplelock_lock(&q->lock);
360 tm = runq_remove_nolock(q);
361 simplelock_unlock(&q->lock);
365 static struct kse_thr_mailbox *
366 runq_remove_nolock(struct uts_runq *q)
368 struct kse_thr_mailbox *p, *p1;
373 for (p = q->head; p->tm_next != NULL; p = p->tm_next)
383 * Userland thread scheduler.
386 uts(struct kse_mailbox *km)
389 static struct uts_data *prev_data;
391 struct kse_thr_mailbox *tm, *p;
392 struct uts_data *data;
395 UPSTR("\n--uts() start--\n");
396 UPFMT("mailbox -> %x\n", km);
399 * Insert any processes back from being blocked
400 * in the kernel into the run queue.
403 p = km->km_completed;
404 km->km_completed = NULL;
405 UPFMT("km_completed -> 0x%x", p);
407 if (data != prev_data) {
409 pfmt("uts data: 0x%x\n", data);
412 while ((tm = p) != NULL) {
415 runq_insert(data->runq, tm);
419 simplelock_lock(&data->runq->lock);
421 * Process any signals we've received (but only if we have
422 * somewhere to deliver them to).
424 if ((data->runq->head != NULL) && SIGNOTEMPTY(km->km_sigscaught)) {
425 for (i = 0;i < _SIG_MAXSIG;i++)
426 if (SIGISMEMBER(km->km_sigscaught, i)) {
427 signalcontext(&data->runq->head->tm_context,
431 bzero(&km->km_sigscaught, sizeof(sigset_t));
435 * Pull a thread off the run queue.
437 p = runq_remove_nolock(data->runq);
438 simplelock_unlock(&data->runq->lock);
440 if ((p == aa) && (progress > 0)) {
442 signalcontext(&p->tm_context, 1, foof);
447 * Either schedule a thread, or idle if none ready to run.
450 UPFMT("\n-- uts() scheduling 0x%x--\n", p);
451 UPFMT("eip -> 0x%x progress -> %d\n",
452 p->tm_context.uc_mcontext.mc_eip, progress);
453 UPSTR("curthread set\n");
454 uts_to_thread(p, &km->km_curthread);
455 UPSTR("\n-- uts_to_thread() failed --\n");
458 pstr("** uts() exiting **\n");
465 static struct kse_thr_mailbox *
466 thread_create(const void *func, int arg)
468 struct kse_thr_mailbox *tm;
471 aa = tm = (struct kse_thr_mailbox *)calloc(1, sizeof(struct kse_thr_mailbox));
472 getcontext(&tm->tm_context);
473 p = (char *)malloc(THREAD_STACK_SIZE);
474 tm->tm_context.uc_stack.ss_sp = p;
475 tm->tm_context.uc_stack.ss_size = THREAD_STACK_SIZE;
476 makecontext(&tm->tm_context, func, 2, arg);
477 // setcontext(&tm->tm_context);
482 thread_start(struct uts_data *data, const void *func, int arg)
484 struct kse_thr_mailbox *tm;
485 struct kse_thr_mailbox *tm2;
487 tm = thread_create(func, arg);
488 tm2 = thread_create(enter_uts, (int)data);
489 tm->tm_context.uc_link = &tm2->tm_context;
490 runq_insert(data->runq, tm);
491 pfmt("thread_start() : 0x%x %x\n", tm, &tm->tm_context);