1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 by Thomas Martitz
12 * Generic unix threading support
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
34 static volatile bool sig_handler_called
;
35 static volatile jmp_buf tramp_buf
;
36 static volatile jmp_buf bootstrap_buf
;
37 static void (*thread_func
)(void);
38 static const int trampoline_sig
= SIGUSR1
;
39 static pthread_t main_thread
;
43 } thread_bufs
[MAXTHREADS
];
44 static struct ctx
* thread_context
, *target_context
;
47 static void trampoline(int sig
);
48 static void bootstrap_context(void) __attribute__((noinline
));
50 /* The *_context functions are heavily based on Gnu pth
51 * http://www.gnu.org/software/pth/
53 * adjusted to work in a multi-thread environment to
54 * offer a ucontext-like API
58 * VARIANT 2: THE SIGNAL STACK TRICK
60 * This uses sigstack/sigaltstack() and friends and is really the
61 * most tricky part of Pth. When you understand the following
62 * stuff you're a good Unix hacker and then you've already
63 * understood the gory ingredients of Pth. So, either welcome to
64 * the club of hackers, or do yourself a favor and skip this ;)
66 * The ingenious fact is that this variant runs really on _all_ POSIX
67 * compliant systems without special platform kludges. But be _VERY_
68 * carefully when you change something in the following code. The slightest
69 * change or reordering can lead to horribly broken code. Really every
70 * function call in the following case is intended to be how it is, doubt
73 * For more details we strongly recommend you to read the companion
74 * paper ``Portable Multithreading -- The Signal Stack Trick for
75 * User-Space Thread Creation'' from Ralf S. Engelschall. A copy of the
76 * draft of this paper you can find in the file rse-pmt.ps inside the
77 * GNU Pth distribution.
80 static int make_context(struct ctx
*ctx
, void (*f
)(void), char *sp
, size_t stack_size
)
91 * Preserve the trampoline_sig signal state, block trampoline_sig,
92 * and establish our signal handler. The signal will
93 * later transfer control onto the signal stack.
96 sigaddset(&sigs
, trampoline_sig
);
97 sigprocmask(SIG_BLOCK
, &sigs
, &osigs
);
98 sa
.sa_handler
= trampoline
;
99 sigemptyset(&sa
.sa_mask
);
100 sa
.sa_flags
= SA_ONSTACK
;
101 if (sigaction(trampoline_sig
, &sa
, &osa
) != 0)
103 DEBUGF("%s(): %s\n", __func__
, strerror(errno
));
109 * For sigaltstack we're lucky [from sigaltstack(2) on
110 * FreeBSD 3.1]: ``Signal stacks are automatically adjusted
111 * for the direction of stack growth and alignment
114 * For sigstack we have to decide ourself [from sigstack(2)
115 * on Solaris 2.6]: ``The direction of stack growth is not
116 * indicated in the historical definition of struct sigstack.
117 * The only way to portably establish a stack pointer is for
118 * the application to determine stack growth direction.''
121 ss
.ss_size
= stack_size
;
123 if (sigaltstack(&ss
, &oss
) < 0)
125 DEBUGF("%s(): %s\n", __func__
, strerror(errno
));
130 * Now transfer control onto the signal stack and set it up.
131 * It will return immediately via "return" after the setjmp()
132 * was performed. Be careful here with race conditions. The
133 * signal can be delivered the first time sigsuspend() is
136 sig_handler_called
= false;
137 main_thread
= pthread_self();
139 sigdelset(&sigs
, trampoline_sig
);
140 pthread_kill(main_thread
, trampoline_sig
);
141 while(!sig_handler_called
)
145 * Inform the system that we are back off the signal stack by
146 * removing the alternative signal stack. Be careful here: It
147 * first has to be disabled, before it can be removed.
149 sigaltstack(NULL
, &ss
);
150 ss
.ss_flags
= SS_DISABLE
;
151 if (sigaltstack(&ss
, NULL
) < 0)
153 DEBUGF("%s(): %s\n", __func__
, strerror(errno
));
156 sigaltstack(NULL
, &ss
);
157 if (!(ss
.ss_flags
& SS_DISABLE
))
159 DEBUGF("%s(): %s\n", __func__
, strerror(errno
));
162 if (!(oss
.ss_flags
& SS_DISABLE
))
163 sigaltstack(&oss
, NULL
);
166 * Restore the old trampoline_sig signal handler and mask
168 sigaction(trampoline_sig
, &osa
, NULL
);
169 sigprocmask(SIG_SETMASK
, &osigs
, NULL
);
172 * Tell the trampoline and bootstrap function where to dump
173 * the new machine context, and what to do afterwards...
176 thread_context
= ctx
;
179 * Now enter the trampoline again, but this time not as a signal
180 * handler. Instead we jump into it directly. The functionally
181 * redundant ping-pong pointer arithmentic is neccessary to avoid
182 * type-conversion warnings related to the `volatile' qualifier and
183 * the fact that `jmp_buf' usually is an array type.
185 if (setjmp(*((jmp_buf *)&bootstrap_buf
)) == 0)
186 longjmp(*((jmp_buf *)&tramp_buf
), 1);
189 * Ok, we returned again, so now we're finished
195 static void trampoline(int sig
)
198 /* sanity check, no other thread should be here */
199 if (pthread_self() != main_thread
)
202 if (setjmp(*((jmp_buf *)&tramp_buf
)) == 0)
204 sig_handler_called
= true;
207 /* longjump'd back in */
211 void bootstrap_context(void)
213 /* copy to local storage so we can spawn further threads
215 void (*thread_entry
)(void) = thread_func
;
216 struct ctx
*t
= thread_context
;
219 * Save current machine state (on new stack) and
220 * go back to caller until we're scheduled for real...
222 if (setjmp(t
->thread_buf
) == 0)
223 longjmp(*((jmp_buf *)&bootstrap_buf
), 1);
226 * The new thread is now running: GREAT!
227 * Now we just invoke its init function....
230 DEBUGF("thread left\n");
234 static inline void set_context(struct ctx
*c
)
236 longjmp(c
->thread_buf
, 1);
239 static inline void swap_context(struct ctx
*old
, struct ctx
*new)
241 if (setjmp(old
->thread_buf
) == 0)
242 longjmp(new->thread_buf
, 1);
245 static inline void get_context(struct ctx
*c
)
247 setjmp(c
->thread_buf
);
251 static void setup_thread(struct regs
*context
);
253 #define INIT_MAIN_THREAD
254 static void init_main_thread(void *addr
)
256 /* get a context for the main thread so that we can jump to it from
258 struct regs
*context
= (struct regs
*)addr
;
259 context
->uc
= &thread_bufs
[curr_uc
++];
260 get_context(context
->uc
);
263 #define THREAD_STARTUP_INIT(core, thread, function) \
264 ({ (thread)->context.stack_size = (thread)->stack_size, \
265 (thread)->context.stack = (uintptr_t)(thread)->stack; \
266 (thread)->context.start = function; })
271 * Prepare context to make the thread runnable by calling swapcontext on it
273 static void setup_thread(struct regs
*context
)
275 void (*fn
)(void) = context
->start
;
276 context
->uc
= &thread_bufs
[curr_uc
++];
277 while (!make_context(context
->uc
, fn
, (char*)context
->stack
, context
->stack_size
))
278 DEBUGF("Thread creation failed. Retrying");
283 * Save the ucontext_t pointer for later use in swapcontext()
285 * Cannot do getcontext() here, because jumping back to the context
286 * resumes after the getcontext call (i.e. store_context), but we need
287 * to resume from load_context()
289 static inline void store_context(void* addr
)
291 struct regs
*r
= (struct regs
*)addr
;
292 target_context
= r
->uc
;
296 * Perform context switch
298 static inline void load_context(const void* addr
)
300 struct regs
*r
= (struct regs
*)addr
;
301 if (UNLIKELY(r
->start
))
306 swap_context(target_context
, r
->uc
);