I took operating systems last year, during which I used user contexts (defined in the header ucontext.h
) to implement a thread scheduler (in which each thread simulated a process) for a project. I'm taking part in a lecture and will talk about user contexts, and it just occurred to me that, despite having done this project last year, I don't really understand what exactly the getcontext
system call actually does.
The man pages for getcontext
states that it
initializes the structure pointed at by ucp to the currently active context."
It also states, for the argument to setcontext
, that if the ucp argument
was obtained by a call of getcontext(), program execution continues as if this call just returned.
Okay, so I understand that.
So here's what I'm confused about. Typically, for the way I learned it, to perform a context switch, one would initialize the ucontext_t
struct and swap/set it as such:
ucontext_t ucp;
ucontext_t oucp;
getcontext(&ucp);
// Initialize the stack_t struct in the ucontext_t struct
ucp.uc_stack.ss_sp = malloc(STACK_SIZE);
ucp.uc_stack.ss_size = STACK_SIZE;
ucp.uc_stack.ss_flags = 0;
ucp.uc_link = /* some other context, or just NULL */;
// Don't block any signals in this context
sigemptyset(&ucp.uc_sigmask);
// Assume that fn is a function that takes 0 arguments and returns void
makecontext(&ucp, fn, 0);
// Perform the context switch. Function 'fn' will be active now
swapcontext(&oucp, &ucp);
// alternatively: setcontext(&ucp);
If I omit getcontext
in smaller programs, nothing interesting happens. In somewhat larger programs in which there is more context switching via user contexts, I get a segmentation fault that is only resolved by adding getcontext
back in.
What exactly does getcontext
do? Why can't I just allocate a ucontext_t
struct, initialize it by initializing the uc_stack
and uc_sigmask
fields, and calling makecontext
without the getcontext
? Is there some necessary initialization that getcontext
performs that makecontext
does not perform?
The function getcontext() initializes the structure pointed to by ucp to the currently active context. The function setcontext() restores the user context pointed to by ucp. A successful call does not return.
DESCRIPTION. The ucontext_t type is a structure type suitable for holding the context for a user thread of execution. A thread's context includes its stack, saved registers, and list of blocked signals. The ucontext_t structure contains at least these fields: ucontext_t *uc_link.
I looked at the GNU libc implementation for ucontext on x86/linux architectures, so, there might be different implementations for which the following does not hold.
The GNU libc manual states that:
The ucp parameter passed to the makecontext shall be initialized by a call to getcontext.
If you look at mcontext_t in glibc/sysdeps/unix/linux/x86/sys/ucontext.h there is a pointer to the floating point state (fpregset_t fpregs) that is initialized in getcontext() and dereferenced again in setcontext(). However, it is not initialized using makecontext(). I did a quick test with GDB and I got a segfault in setcontext() when trying to dereference the pointer to the floating point context in a ucontext_t struct not initialized by getcontext():
=> 0x00007ffff784308c <+44>: fldenv (%rcx)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With