Skip to content

Instantly share code, notes, and snippets.

@elliott-beach
Created October 12, 2017 20:10
Show Gist options
  • Save elliott-beach/c52300a30db2c6dc744a5c9e5e107b22 to your computer and use it in GitHub Desktop.
Save elliott-beach/c52300a30db2c6dc744a5c9e5e107b22 to your computer and use it in GitHub Desktop.
Comments on setjmp
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
char stack1[STACK_SIZE];
char stack2[STACK_SIZE];
// This is the Thread Control Block. We can use the same structure for our htreading,
// but with 1000 instead of 2.
sigjmp_buf jbuf[2];
void switchThreads();
void f()
{
int i=0;
while(1) {
++i;
printf("in f (%d)\n",i);
if (i % 3 == 0) {
printf("f: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
void g()
{
int i=0;
while(1){
++i;
printf("in g (%d)\n",i);
if (i % 5 == 0) {
printf("g: switching\n");
switchThreads();
}
usleep(SECOND);
}
}
#ifdef __x86_64__
/* code for 64 bit Intel arch */
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
/* code for 32 bit Intel arch */
typedef unsigned int address_t;
#define JB_SP 4
#define JB_PC 5
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
void setup()
{
address_t sp, pc;
// Make thread 1's stack point to memory on the data section.
sp = (address_t)stack1 + STACK_SIZE - sizeof(int);
// Make thread 1's program counter point to f.
pc = (address_t)f;
// Copy sp,pc into the jmpbuf struct.
sigsetjmp(jbuf[0],1);
(jbuf[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(jbuf[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&jbuf[0]->__saved_mask);
// Make thread 2's stack point to memory on the data section.
sp = (address_t)stack2 + STACK_SIZE - sizeof(int);
// Make thread 2's program counter point to g.
pc = (address_t)g;
// Copy sp,pc into the jmpbuf struct.
sigsetjmp(jbuf[1],1);
(jbuf[1]->__jmpbuf)[JB_SP] = translate_address(sp);
(jbuf[1]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&jbuf[1]->__saved_mask);
}
void switchThreads()
{
static int currentThread = 0;
// thread_yield() and premption will return to this point.
int ret_val = sigsetjmp(jbuf[currentThread],1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1) {
return;
}
// TODO: we will handle scheduling threads here.
currentThread = 1 - currentThread;
siglongjmp(jbuf[currentThread],1);
}
int main()
{
setup();
siglongjmp(jbuf[0],1);
return 0;
}
Copy link

ghost commented Oct 14, 2017

I wasn't really sure what the fields of the sigjmp struct are. I think that these are roughly what the fields of the struct sigjmp look like as well the jmpbuf buffer.

struct sigjmp_buf {
/* NOTE: The machine-dependent definitions of __sigsetjmp' assume that a jmp_buf' begins with a __jmp_buf' and that __mask_was_saved' follows it. Do not move these members
or add others before it. /
__jmp_buf __jmpbuf; /
Calling environment. /
int __mask_was_saved; /
Saved the signal mask? /
__sigset_t __saved_mask; /
Saved signal mask. */
};

On second thought, I think it's heavily architecture dependent, but it's at least something like this. I guess the demo makes it clear what the implementation looks like.

jmp_buf:
offset size description
0 16 call-saved registers (r2-r17)
16 2 frame pointer (r29:r28)
18 2 stack pointer (SPH:SPL)
20 1 status register (SREG)
21 3 return address (PC) (2 bytes used for <=128K flash)
24 = total size

@nimit95
Copy link

nimit95 commented Mar 9, 2019

I am confused on macOS, I have sigjmp_buf as unsigned int array, how to set value of pc and sp to it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment