/* * tfork(function, argument): starts a new thread of execution running * in the same address space. The new thread gets its own 4K stack, * and starts at the address in "function" with "argument" on the stack, * i.e. as though the main program had a call like "function(argument)". * The main program continues executing, with tfork returning the process * i.d. of the child. * (if MiNT is not active, then the child runs first to completion * and the return value is the child's exit status; vfork() relies this * behavior) * * Note that parent and child share the same memory; this could cause * problems with some library calls, notably malloc(). */ #include #include #include #include #include #include #include #define SIZE 4096L extern int __mint; extern long _childtime; /* in main.c */ extern long _sigpending, _sigmask; /* in signal.c */ extern __Sigfunc _sig_handler[NSIG]; /* ditto */ /* this is used by wait() and wait3() to retrieve the child's exit code */ long __waitval = -ENOENT; /* and this is used to retrieve the child's time */ long __waittime = 0; static void startup(b) register BASEPAGE *b; { register int (*func)(); register long arg; extern void _setstack(); /* in crt0.s */ _setstack( ((long)b) + SIZE ); func = (int (*)())b->p_dbase; arg = b->p_dlen; Pterm(func(arg)); } /* use long instead of int so vfork works OK with -mshort */ long tfork(func, arg) int (*func)(); long arg; { register BASEPAGE *b; register long pid; register long savpending, savmask; register BASEPAGE *savbase; __Sigfunc savhandler[NSIG]; long now; int i; b = (BASEPAGE *)Pexec(PE_CBASEPAGE, 0L, "", 0L); (void)Mshrink(b, SIZE); b->p_tbase = (char *)startup; b->p_dbase = (char *)func; b->p_dlen = arg; if (__mint) pid = Pexec(104, 0L, b, 0L); else { /* save the signal masks and signal handlers, the child may change them */ savpending = _sigpending; _sigpending = 0; savmask = _sigmask; _sigmask = 0; for (i = 0; i < NSIG; i++) savhandler[i] = _sig_handler[i]; savbase = _base; _base = b; now = clock(); pid = Pexec(4, 0L, b, 0L); (void)Mfree((long)b->p_env); /* free the memory */ (void)Mfree((long)b); _base = savbase; /* restore signal stuff */ for (i = 0; i < NSIG; i++) _sig_handler[i] = savhandler[i]; _sigmask = savmask; _sigpending = savpending; if (pid >= 0) { int retval = pid; /* see the TOS algorithm for getpid() */ pid = ((long)b) >> 8; __waitval = (pid << 16) | retval; raise(SIGCHLD); __waittime = clock() - now; _childtime += __waittime; } } return pid; }