2006-02-27 Roland McGrath <roland@redhat.com>
[glibc-ports.git] / sysdeps / unix / sysv / linux / alpha / clone.S
blob5e0b21ea1574bc177d8f4ae7b41113e5aca44325
1 /* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Richard Henderson <rth@tamu.edu>, 1996.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
20 /* clone() is even more special than fork() as it mucks with stacks
21    and invokes a function in the right context after its all over.  */
23 #include <sysdep.h>
24 #define _ERRNO_H        1
25 #include <bits/errno.h>
27 #define CLONE_VM        0x00000100
28 #define CLONE_THREAD    0x00010000
30 /* int clone(int (*fn)(void *arg), void *child_stack, int flags,
31              void *arg, pid_t *ptid, void *tls, pid_t *ctid);
33    Note that everything past ARG is technically optional, based
34    on FLAGS, and that CTID is arg 7, and thus is on the stack.
35    However, since a load from top-of-stack better be legal always,
36    we don't bother checking FLAGS.  */
38         .text
39 ENTRY(__clone)
40 #ifdef PROF
41         ldgp    gp,0(pv)
42         .set noat
43         lda     AT, _mcount
44         jsr     AT, (AT), _mcount
45         .set at
46         .prologue 1
47 #else
48         .prologue 0
49 #endif
51         /* Sanity check arguments.  */
52         ldiq    v0,EINVAL
53         beq     a0,$error               /* no NULL function pointers */
54         beq     a1,$error               /* no NULL stack pointers */
56         /* Save the fn ptr and arg on the new stack.  */
57         subq    a1,32,a1
58         stq     a0,0(a1)
59         stq     a3,8(a1)
60 #ifdef RESET_PID
61         stq     a2,16(a1)
62 #endif
64         /* The syscall is of the form clone(flags, usp, ptid, ctid, tls).
65            Shift the flags, ptid, ctid, tls arguments into place; the
66            child_stack argument is already correct.  */
67         mov     a2,a0
68         mov     a4,a2
69         ldq     a3,0(sp)
70         mov     a5,a4
72         /* Do the system call.  */
73         ldiq    v0,__NR_clone
74         call_pal PAL_callsys
76         bne     a3,$error
77         beq     v0,thread_start
79         /* Successful return from the parent.  */
80         ret
82         /* Something bad happened -- no child created.  */
83 $error:
84 #ifndef PROF
85         br      gp,1f
86 1:      ldgp    gp,0(gp)
87 #endif
88         SYSCALL_ERROR_HANDLER
90         END(__clone)
92 /* Load up the arguments to the function.  Put this block of code in
93    its own function so that we can terminate the stack trace with our
94    debug info.  */
96         .ent thread_start
97 thread_start:
98         .frame  fp,0,fp,0
99         mov     0, fp
100         .prologue 0
102 #ifdef RESET_PID
103         /* Check and see if we need to reset the PID.  */
104         ldq     t0,16(sp)
105         lda     t1,CLONE_THREAD
106         and     t0,t1,t2
107         beq     t2,2f
109 #endif
111         /* Load up the arguments.  */
112         ldq     pv,0(sp)
113         ldq     a0,8(sp)
114         addq    sp,32,sp
116         /* Call the user's function.  */
117         jsr     ra,(pv)
118         ldgp    gp,0(ra)
120         /* Call _exit rather than doing it inline for breakpoint purposes.  */
121         mov     v0,a0
122 #ifdef PIC
123         bsr     ra, HIDDEN_JUMPTARGET(_exit)    !samegp
124 #else
125         jsr     ra, HIDDEN_JUMPTARGET(_exit)
126 #endif
128         /* Die horribly.  */
129         halt
131 #ifdef RESET_PID
133         rduniq
134         lda     t1, CLONE_VM
135         mov     v0, s0
136         lda     v0, -1
137         and     t0, t1, t2
138         bne     t2, 3f
139         lda     v0, __NR_getxpid
140         callsys
142         stl     v0, PID_OFFSET(s0)
143         stl     v0, TID_OFFSET(s0)
144         br      1b
145 #endif
147         .end thread_start
149 weak_alias (__clone, clone)