Question

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?

Was it helpful?

Solution

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top