home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / bbs / gnu / aplusplus-1.01-src.lha / GNU / src / amiga / APlusPlus-1.01 / amiproc / amiproc.c next >
C/C++ Source or Header  |  1994-01-14  |  11KB  |  318 lines

  1.  
  2. /* Copyright (c) 1989-1994, Steve Krueger and Doug Walker, Raleigh, NC. */
  3. /* All Rights Reserved.                                                 */
  4.  
  5. /* NOTE: Define the preprocessor symbol NOOLDDOS when compiling to */
  6. /* save a little space if your program will never be run under     */
  7. /* AmigaDOS 1.3 or earlier.                                        */
  8.  
  9. /* We need _USEOLDEXEC_ to ensure that the extern SysBase isn't used */
  10. /* to access exec.library.  Since we're mucking about with our near  */
  11. /* data register, we don't want to rely on near data to make exec    */
  12. /* calls!                                                            */
  13. #define _USEOLDEXEC_ 1
  14.  
  15. #include <exec/memory.h>
  16. #include <exec/execbase.h>
  17. #include <libraries/dosextens.h>
  18. #include <dos/dostags.h>
  19. #include <proto/exec.h>
  20. #include <proto/dos.h>
  21.  
  22. #include <dos.h>
  23. #include <string.h>
  24.  
  25. #include "amiproc.h"
  26.  
  27. extern struct ExecBase *SysBase;
  28.  
  29. // Functions defined in the SAS/C® library to run autoinitializer
  30. // and autoterminater functions
  31. void __stdargs __fpinit(void);
  32. void __stdargs __fpterm(void);
  33.  
  34. // Data items defined in the SAS/C® library and possibly overridden
  35. // by user code.  __stack gives the desired stack size, __priority
  36. // gives the desired priority, and __procname gives the desired name
  37. // for any new processes.
  38. extern long __stack, __priority;
  39. extern char *__procname;
  40.  
  41. extern char __far RESLEN;               /* size of init data   */
  42. extern char __far RESBASE;              /* Base of global data */
  43. extern char __far NEWDATAL;             /* size of global data */
  44. extern const char __far LinkerDB;       /* Original A4 value   */
  45. extern struct DosLibrary *DOSBase;
  46. extern struct ExecBase *SysBase;
  47. extern char *_ProgramName;
  48. BPTR __curdir;
  49.  
  50. static struct DosLibrary *MyDOSBase;
  51.  
  52. #define DATAWORDS ((ULONG)&NEWDATAL)     /* magic to get right type of reloc */ 
  53.  
  54. static long _CloneData(void)
  55. {
  56.    ULONG *newa4;
  57.    ULONG *origa4;
  58.    ULONG *reloc;
  59.    ULONG nrelocs;
  60.    struct WBStartup *wbtmp = _WBenchMsg;
  61.    char *pntmp = _ProgramName;
  62.    BPTR cdtmp = __curdir;
  63.  
  64.    // Allocate the new data section
  65.    newa4 = (ULONG *)AllocMem((ULONG)&RESLEN, MEMF_PUBLIC);
  66.    if(newa4 == NULL) return NULL;
  67.  
  68.    // Get original A4 value
  69.    // This points to the UNMODIFIED near global data section
  70.    // allocated by the cres.o startup.  This line of code 
  71.    // will also generate a linker warning; ignore it.
  72.    origa4 = (ULONG *)((ULONG)&LinkerDB - (ULONG)&RESBASE);
  73.  
  74.    // Copy over initialized data
  75.    memcpy(newa4, origa4, DATAWORDS*4);
  76.    
  77.    // Zero uninitialized data
  78.    memset(newa4+DATAWORDS, 0, (((ULONG)&RESLEN)-DATAWORDS*4));
  79.  
  80.    // Perform relocations
  81.    // The number of relocs is stashed immediately after the
  82.    // initialized data in the original data section.  The
  83.    // relocs themselves follow.
  84.    origa4 += DATAWORDS;
  85.    for(nrelocs = *origa4++; nrelocs>0; nrelocs--)
  86.    {
  87.       reloc = (ULONG *)((ULONG)newa4 + *origa4++);
  88.       *reloc += (ULONG)newa4;
  89.    }
  90.  
  91.    // If your code has >32k of near data, RESBASE will be 32k.
  92.    // Otherwise, it will be 0.  The A4 pointer must point into
  93.    // the middle of the data section if you have >32k of data
  94.    // because the A4-relative addressing mode can handle +/-32k
  95.    // of data, not 64k of positive data.
  96.    newa4 += (ULONG)&RESBASE;
  97.    putreg(REG_A4, (long)newa4);
  98.  
  99.    // Set up a couple of externs that the startup code normally
  100.    // does for you...
  101.    SysBase = *(struct ExecBase **)4;
  102.    MyDOSBase = DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0L);
  103.    _WBenchMsg = wbtmp;       // Copied from old data section
  104.    _ProgramName = pntmp;     // Copied from old data section
  105.    __curdir = DupLock(cdtmp);// cdtmp copied from old data section
  106.  
  107.    return (long)newa4;
  108. }
  109.  
  110. static void _FreeData(void)
  111. {
  112.    // Free the current directory lock
  113.    UnLock(__curdir);
  114.  
  115.    // Close the local static copy of MyDOSBase
  116.    CloseLibrary((struct Library *)MyDOSBase);
  117.    
  118.    // Free the new data section we allocated
  119.    FreeMem((void *)getreg(REG_A4), (ULONG)&RESLEN);
  120. }
  121.  
  122. struct FAKE_SegList {
  123.    long space;
  124.    long length;
  125.    BPTR nextseg;
  126.     short jmp;
  127.     void (*func)(void);
  128. };
  129.  
  130. struct AmiProcMsg {                     /* startup message sent to child */
  131.         struct Message msg;
  132.         int (*fp)(void *);              /* function we're going to call */
  133.         void *global_data;              /* global data reg (A4)         */
  134.         long return_code;               /* return code from process     */
  135.         struct FAKE_SegList *seg;       /* pointer to fake seglist so   */
  136.                                         /* can it can be free'd         */
  137.         void *UserData;                 /* User-supplied data pointer   */
  138.         };
  139.  
  140.  
  141. static void process_starter(void)
  142. {
  143.    struct Process *proc;
  144.    struct AmiProcMsg *mess;
  145.    __regargs int (*fp)(void *, void *, void *);
  146.          
  147.    proc = (struct Process *)FindTask((char *)NULL);
  148.  
  149.    /* get the startup message */
  150.    WaitPort(&proc->pr_MsgPort);
  151.    mess = (struct AmiProcMsg *)GetMsg(&proc->pr_MsgPort);
  152.  
  153.    /* gather necessary info from message */
  154.    fp = (__regargs int (*)(void *, void *, void *))mess->fp;
  155.  
  156.    /* replace this with the proper #asm for Aztec */
  157.    putreg(REG_A4, (long)mess->global_data);
  158.    
  159.    /* Allocate a new data section */
  160.    putreg(REG_A4, _CloneData());
  161.  
  162.    /* Run autoinitializers.  This has the effect of setting up    */
  163.    /* the standard C and C++ libraries (including stdio), running */
  164.    /* constructors for C++ externs and statics, and running user  */
  165.    /* autoinit functions.                                         */
  166.    __fpinit();
  167.  
  168.    /* Call the desired function */
  169.    /* We pass the UserData parameter three times in order to satisfy */
  170.    /* both PARM=REG and PARM=STACK function pointers.  Since we have */
  171.    /* declared the local 'fp' to be regargs, the three parms will go */
  172.    /* into A0, A1 and the stack.  If 'fp' points to a regargs func,  */
  173.    /* it will get its parm from A0 and all is well.  If 'fp' points  */
  174.    /* to a stdargs func, it will get its parameter from the stack and*/
  175.    /* all is still well.                                             */
  176.    mess->return_code = (*fp)(mess->UserData, mess->UserData, mess->UserData);
  177.  
  178.    /* Run autoterminators to clean up. */
  179.    __fpterm();
  180.    
  181.    /* Free the recently-allocated data section */
  182.    _FreeData();
  183.    
  184.    /* Forbid so the child can finish completely, before */
  185.    /* the parent cleans up.                             */
  186.    Forbid();
  187.  
  188.    /* Reply so process who spawned us knows we're done */   
  189.    ReplyMsg((struct Message *)mess);
  190.  
  191.    /* We finish without Permit()ing, but it's OK since our task    */
  192.    /* will end after the RTS, which will break the Forbid() anyway */
  193. }
  194.  
  195.  
  196. // AmiProc_Start - launch a new process with a specified function
  197. // pointer as the entry point.
  198. struct AmiProcMsg *AmiProc_Start(int (*fp)(void *), void *UserData)
  199. {
  200.    struct Process *process;
  201.    struct MsgPort *child_port;
  202.    struct AmiProcMsg *start_msg;
  203.    BPTR in, out;
  204. #ifndef NOOLDDOS
  205.    struct FAKE_SegList *seg_ptr;
  206. #endif
  207.    int stack = (__stack > 4000 ? __stack : 4000);
  208.    char *procname = (__procname ? __procname : "New Process");
  209.    
  210.    start_msg = (struct AmiProcMsg *)AllocMem(sizeof(struct AmiProcMsg), 
  211.                                           MEMF_PUBLIC|MEMF_CLEAR);
  212.    if (start_msg == NULL)
  213.       return NULL;
  214.  
  215. #ifndef NOOLDDOS
  216.    if(SysBase->LibNode.lib_Version > 36)
  217.    {
  218.       seg_ptr = NULL;  // We're not gonna use this, so null it
  219. #endif
  220.  
  221.       if(!(in  = Open("*", MODE_OLDFILE))) in  = Open("NIL:", MODE_NEWFILE);
  222.       if(!(out = Open("*", MODE_OLDFILE))) out = Open("NIL:", MODE_NEWFILE);
  223.  
  224.       /* Flush the data cache in case we're on a 68040 */
  225.       CacheClearU();
  226.  
  227.       process =   CreateNewProcTags(NP_Entry,     process_starter,
  228.                                     NP_StackSize,  stack,
  229.                                     NP_Name,       procname,
  230.                                     NP_Priority,   __priority,
  231.                                     NP_Input,      in,
  232.                                     NP_Output,     out,
  233.                                     TAG_END);
  234.       child_port = process ? &process->pr_MsgPort : NU