home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / sys / hp / 14227 < prev    next >
Encoding:
Internet Message Format  |  1992-12-21  |  8.6 KB

  1. From: cary@hpcuhe.cup.hp.com (Cary Coutant)
  2. Date: Fri, 18 Dec 1992 00:15:12 GMT
  3. Subject: Re: problems with setjmp(3C),longjmp(3C)
  4. Message-ID: <31480302@hpcuhe.cup.hp.com>
  5. Organization: Hewlett Packard, Cupertino
  6. Path: sparky!uunet!cs.utexas.edu!sdd.hp.com!hpscit.sc.hp.com!hplextra!hpfcso!hpcss01!hpcuhe!cary
  7. Newsgroups: comp.sys.hp
  8. References: <1992Dec17.131523.11740@Informatik.TU-Muenchen.DE>
  9. Lines: 340
  10.  
  11. > I'm trying to port a distributed system to a HP9000/710 running
  12. > HP-UX 8.07. This system uses setjmp and longjmp for task switching.
  13. > I need to access stackpointer and framepointer through the jmp_buf
  14. > structure but nowhere in the HP documentation and also not in
  15. > /usr/include/setjmp.h there is information on the position in 
  16. > jmp_buf where the contents of the dumped registers are stored.
  17.  
  18. On PA, there is (usually) no framepointer.  Instead, stack frames
  19. are a fixed size, and are created and destroyed on entry and exit.
  20. I don't know if this is a problem for the package you're trying
  21. to port.
  22.  
  23. > In the porting notes of the system is also read: 
  24. > "It is not possible to use setjmp or longjmp on some systems
  25. >  either because they contain bugs and fail to restore state
  26. >  properly, or because they check that longjmp only returns to
  27. >  a previously encountered stack frame, i.e setjmp was previously
  28. >  executed on the current stack."
  29.  
  30. No problems here, though.
  31.  
  32. > So my questions are:
  33. > - What registers are stored in what order in jmp_buf ?
  34.  
  35. rp and sp are saved in the first two words, respectively,
  36. followed by the signal mask and an on-signal-stack flag.
  37. Then the entry save registers (gr3-18) are saved.
  38. Then gr19, sr3, fr12-15, a one-word flag indicating
  39. whether the signal mask should be restored, a one-word
  40. hole, fr16-21, rp-prime, and external-dp.
  41.  
  42. >   - If not how would assembly routines look like that could be 
  43. >     used instead ?
  44.  
  45. I've attached below a simple user-level thread package that you might
  46. be able to use.
  47.  
  48.  
  49. Cary Coutant
  50. Hewlett-Packard
  51. California Language Lab
  52.  
  53.  
  54. # This is a shell archive.  Remove anything before this line,
  55. # then unpack it by saving it in a file and typing "sh file".
  56. #
  57. # Wrapped by Cary Coutant <cary@hpclpax> on Thu Dec 17 16:16:02 1992
  58. #
  59. # This archive contains:
  60. #    threads.s    forks.c        Makefile    
  61. #
  62.  
  63. LANG=""; export LANG
  64. PATH=/bin:/usr/bin:$PATH; export PATH
  65.  
  66. echo x - threads.s
  67. cat >threads.s <<'@EOF'
  68.     .copyright "Hewlett Packard, 1992"
  69.  
  70. ; Thread Control Block structure
  71. ;
  72. ; struct tcb {
  73. ;     long tcb_sp;
  74. ;     long tcb_stackbase;
  75. ;     long tcb_stacklimit;
  76. ;     /* anything else you may want */
  77. ;     }
  78.  
  79. TCB_SP        .equ    0
  80. TCB_STACKBASE    .equ    4
  81. TCB_STACKLIMIT    .equ    8
  82.  
  83.  
  84. psp        .equ    64        ; pseudo-register for previous sp
  85.  
  86.  
  87.  
  88. ; long *init_thread_stack(
  89. ;        void (*code)(void),
  90. ;        void *base,
  91. ;        long size)
  92. ;
  93. ; Initializes a new thread's stack and returns the value of the
  94. ; stack pointer that the thread should initially use.
  95. ;
  96. ; <code> is the address of the function where the new thread will start.
  97. ;
  98. ; <base> is the base of the stack that has been allocated for the thread.
  99. ;
  100. ; <size> is the size of the stack.
  101. ;
  102. ; The stack frame is arranged so that it looks like the new thread
  103. ; has suspended execution at the beginning of __thread_init.  When
  104. ; the new thread is resumed, __thread_init (below) will then call
  105. ; the function <code>.
  106.  
  107.     .code
  108.  
  109.     .proc
  110.  
  111.     ; ------------------------NOTE--------------------------
  112.     ; Use the first .callinfo for PA-RISC 1.0 machines.
  113.     ; Use the second for PA-RISC 1.1 machines.
  114.     ; .callinfo calls,save_rp,entry_gr=18,entry_fr=15,entry_sr=3
  115.     ; .callinfo calls,save_rp,entry_gr=18,entry_fr=21,entry_sr=3
  116.     ; ------------------------------------------------------
  117.  
  118.     .callinfo calls,save_rp,entry_gr=18,entry_fr=15,entry_sr=3
  119.     .export init_thread_stack,entry
  120.  
  121. init_thread_stack
  122.     .enter
  123.  
  124.     ; Calculate far end of stack and align to 64-byte boundary
  125.     add    %arg1,%arg2,%r22
  126.     depi    0,31,6,%r22
  127.  
  128.     ; Align base of stack to 64-byte boundary
  129.     ; and allocate a 64-byte stack frame
  130.     ; (This will be __thread_init's stack frame)
  131.     ldo    64+63(%arg1),%arg1
  132.     depi    0,31,6,%arg1
  133.  
  134.     ; Store "magic number" at far end of stack for overflow detection
  135.     mfctl    %cr16,%r21        ; use interval timer as random no.
  136.     uaddcm    %r0,%r21,%r20
  137.     stw    %r21,-32(%r22)         ; Store Cr16 to AlgnLimit-32
  138.     stw    %r20,-16(%r22)        ; Store ~Cr16 to AlgnLimit-16
  139.  
  140.     ; Mark the bottom of the new stack by storing zero in
  141.     ; the saved sp location (sp-4 of the new stack)
  142.     stw    %r0,-4(%arg1)
  143.  
  144.     ; Set the saved rp in __thread_init's stack frame so that execution
  145.     ; begins in the new thread at __thread_init
  146.     ldil    L'__thread_init,%r1
  147.     ldo    R'__thread_init(%r1),%r1
  148.     stw    %r1,-20(%arg1)        ; store at -20(new psp)
  149.  
  150.     ; Save the <code> parameter in the new stack frame
  151.     ; (in __thread_init's parameter area)
  152.     stw    %arg0,-36(%arg1)
  153.  
  154.     ; Create a second stack frame on the new stack the same size
  155.     ; as our stack frame
  156.     ; (This will look like switch_thread's stack frame)
  157.     ; (The register save area will be garbage, but it doesn't matter)
  158.     ldo    0(psp),%r19
  159.     sub    %sp,%r19,%r20
  160.     add    %r20,%arg1,%arg1
  161.  
  162.     ; return the top of stack for the new thread
  163.     copy    %arg1,%ret0
  164.  
  165.     .leave
  166.  
  167.     .procend
  168.  
  169.  
  170.  
  171. ; __thread_init(void (*code)(void))
  172. ;
  173. ; Thread execution begins here upon return from switch_thread.
  174. ; The <code> parameter was saved in the parameter save area by
  175. ; init_thread_stack, so it must be picked up again from there.
  176. ;
  177. ; This is an internal routine.  It is never really "called";
  178. ; instead, it is "returned into" from switch_thread the first
  179. ; time that a thread is resumed.
  180.  
  181.     .proc
  182.     .callinfo calls,save_sp
  183.     .export    __thread_init,entry
  184.  
  185. __thread_init
  186.     ; No entry sequence -- the stack frame was already initialized
  187.     ; for us by init_thread_stack
  188.  
  189.     ; Retrieve the <code> parameter from the stack frame
  190.     ldw    -36(%sp),%arg0
  191.  
  192.     ; Call <code> (in r3) to initiate new thread
  193.     bl    .+8,%rp
  194.     bv,n    0(%arg0)
  195.  
  196.     ; control should never return here
  197.     break    0,0
  198.  
  199.     .procend
  200.  
  201.  
  202.  
  203. ; void switch_thread(struct tcb *new_thread)
  204. ;
  205. ; Transfers control from one thread to another.
  206. ; Saves minimal state of the old thread and restores
  207. ; minimal state for the new thread.
  208. ;
  209. ; init_thread_stack and switch_thread must have identical frame sizes.
  210.  
  211.     .proc
  212.  
  213.     ; ------------------------NOTE--------------------------
  214.     ; Use the first .callinfo for PA-RISC 1.0 machines.
  215.     ; Use the second for PA-RISC 1.1 machines.
  216.     ; .callinfo calls,save_rp,entry_gr=18,entry_fr=15,entry_sr=3
  217.     ; .callinfo calls,save_rp,entry_gr=18,entry_fr=21,entry_sr=3
  218.     ; ------------------------------------------------------
  219.  
  220.     .callinfo calls,save_rp,entry_gr=18,entry_fr=15,entry_sr=3
  221.     .export switch_thread,entry
  222.  
  223. switch_thread
  224.     .enter
  225.  
  226.     ; Get address of current thread's TCB from <cur_thread>
  227.     .import cur_thread,data
  228.     .import    $global$,data
  229.     addil    L'cur_thread-$global$,%dp
  230.     ldw    R'cur_thread-$global$(%r1),%r19
  231.  
  232.     ; Check for stack overflow
  233.     ldw    TCB_STACKLIMIT(%r19),%r20
  234.     depi    0,31,6,%r20    
  235.     ldw    -16(%r20),%r22
  236.     ldw    -32(%r20),%r21
  237.     uaddcm    %r0,%r22,%r22
  238.     xor,=    %r22,%r21,%r0
  239.     break    0,0
  240.  
  241.     ; Switch stacks
  242.     stw    %sp,TCB_SP(%r19)    ; save old thread's sp in its TCB
  243.     ldw    TCB_SP(%arg0),%sp    ; get new thread's sp from <new_thread>
  244.  
  245.     ; We continue here, now on the new thread's stack.
  246.     ; Put address of new TCB in <cur_thread>
  247.     ;addil    L'cur_thread-$global$,%dp ; (r1 is still live from above)
  248.     stw    %arg0,R'cur_thread-$global$(%r1)
  249.     
  250.     .leave
  251.  
  252.     .procend
  253.  
  254.     .end
  255. @EOF
  256.  
  257. chmod 644 threads.s
  258.  
  259. echo x - forks.c
  260. cat >forks.c <<'@EOF'
  261. #define STACKSIZE 65536
  262.  
  263. struct tcb {
  264.     char *sp;
  265.     char *base;
  266.     char *limit;
  267.     };
  268.  
  269. struct tcb tcb[3] = {0};
  270. struct tcb *cur_thread = &tcb[0];
  271.  
  272. char stack1[STACKSIZE] = {0};
  273. char stack2[STACKSIZE] = {0};
  274. char stack3[STACKSIZE] = {0};
  275.  
  276. extern char *init_thread_stack(void (*proc)(void), char *base, int size);
  277. extern void switch_thread(struct tcb *new_thread);
  278.  
  279. #pragma align 64
  280. int limit[16] = {0};
  281.  
  282. int main(int argc, char **argv)
  283.     {
  284.     int i, ub;
  285.     extern void fork1(void), fork2(void);
  286.  
  287.     if (argc > 1)
  288.     ub = atoi(argv[1]);
  289.     else
  290.     ub = 20;
  291.  
  292.     tcb[0].limit = (char *)&limit[16];
  293.     limit[12] = -1;
  294.  
  295.     tcb[1].sp = init_thread_stack(fork1, stack1, STACKSIZE);
  296.     tcb[1].base = stack1;
  297.     tcb[1].limit = stack1 + STACKSIZE;
  298.  
  299.     tcb[2].sp = init_thread_stack(fork2, stack2, STACKSIZE);
  300.     tcb[2].base = stack2;
  301.     tcb[2].limit = stack2 + STACKSIZE;
  302.  
  303.     for (i = 0; i < ub; i++) {
  304.     switch_thread(&tcb[1]);
  305.     switch_thread(&tcb[2]);
  306.     }
  307.     }
  308.  
  309. void fork1(void)
  310.     {
  311.     int i;
  312.     extern void fork1b(void);
  313.  
  314.     for (i = 0; ; i++) {
  315.     printf("%d\n", i);
  316.     switch_thread(&tcb[0]);
  317.     }
  318.     }
  319.  
  320. void fork2(void)
  321.     {
  322.     int i, j, k;
  323.     i = 0;
  324.     j = 1;
  325.     for (;;) {
  326.     printf("\t%d\n", j);
  327.     switch_thread(&tcb[0]);
  328.     k = i + j;
  329.     i = j;
  330.     j = k;
  331.     }
  332.     }
  333. @EOF
  334.  
  335. chmod 644 forks.c
  336.  
  337. echo x - Makefile
  338. cat >Makefile <<'@EOF'
  339. CFLAGS = -O -Aa
  340. LDFLAGS = -Wl,-a,archive
  341.  
  342. OBJS = forks.o threads.o
  343.  
  344. forks:     $(OBJS)
  345.     $(CC) -o forks $(LDFLAGS) $(OBJS)
  346. @EOF
  347.  
  348. chmod 644 Makefile
  349.  
  350. exit 0
  351.