gbbrooks@acsu.buffalo.edu (george b brooks) (03/06/91)
I've been having difficulty trying to use AmigaDOS's processes. I'm using Benchmark Modula-2, and my difficulty resides in the calls to 'CreateProc' and 'LoadSeg'. The problem stems from the fact that I do NOT know really how LoadSeg works. Does load seg work like: Segment := LoadSeg("df1:HelloWorld"); ID := CreateProc(ADR("NewProcess"),0D,Segment,10000D); (Where HelloWorld is a compiled M-2 program on disk) Or like..... Segment := LoadSeg(ADR(HelloWorldProcedure)); ID := CreateProc(ADR("NewProcess"),0D,Segment,10000D); (Where HelloWorldProcedure is a M-2 procedure in the same code) Or what DOES LoadSeg do? Or, rather, I'd like to find out how to create a new process executing concurrently with my original process from either a procedure or a compiled (and linked :-) ) file.... the above two do NOT work. The first one does NOT make an error, yet no second process is started. The second one gurus the system with error 4 (address?) -Thanks, Brandon!
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/06/91)
In article <19578@cbmvax.commodore.com>, ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: > LoadSeg() needs a BPTR to a seg list, which can be faked > like: > > /* From Mike Sinz AmigaMail example */ > struct CodeHdr > { > ULONG SegSize; /* sizeof(struct CodeHdr) */ > ULONG NextSeg; /* Must be NULL */ > UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ > APTR Function; /* a pointer to the function */ > } I'd call this self-modifying code. Ralph
ken@cbmvax.commodore.com (Ken Farinsky - CATS) (03/07/91)
In article <63329@eerie.acsu.Buffalo.EDU> gbbrooks@acsu.buffalo.edu (george b brooks) writes: > Segment := LoadSeg("df1:HelloWorld"); > ID := CreateProc(ADR("NewProcess"),0D,Segment,10000D); > (Where HelloWorld is a compiled M-2 program on disk) > > Segment := LoadSeg(ADR(HelloWorldProcedure)); > ID := CreateProc(ADR("NewProcess"),0D,Segment,10000D); > (Where HelloWorldProcedure is a M-2 procedure in the same code) > > Or what DOES LoadSeg do? Or, rather, I'd like to find out how to >create a new process executing concurrently with my original process from >either a procedure or a compiled (and linked :-) ) file.... the above two >do NOT work. The first one does NOT make an error, yet no second process >is started. The second one gurus the system with error 4 (address?) Its been a while since I've worked with these calls, so these answers may be a bit off. LoadSeg() takes a file name and returns a BPTR to a seg list: BPTR LoadSeg( UBYTE *name ); CreateProc() takes the BPTR returned by LoadSeg(), or any other BPTR to a seg list: struct MsgPort *CreateProc( UBYTE *name, long pri, BPTR segList, long stackSize ); Note that CreateProc() does not return a pointer to the process structure, it returns a pointer to the message port in the process structure. Remember that, in general, code started from disk is compiled with standard startups. When you use LoadSeg(), the code thinks its started from workbench, so you have to send the process a startup message, and hang around for the reply and unload the code when done... The code in the first example is waiting for something to send it a WBStartup message. The second case is incorrect. LoadSeg() needs a BPTR to a seg list, which can be faked like: /* From Mike Sinz AmigaMail example */ struct CodeHdr { ULONG SegSize; /* sizeof(struct CodeHdr) */ ULONG NextSeg; /* Must be NULL */ UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ APTR Function; /* a pointer to the function */ } CreateProc() takes a BPTR to the NextSeg field of this structure. If you are really interested in this, I would recommend purchasing the AmigaMail Volume I notebook from CATS: CATS Orders 1200 Wilson Drive West Chester, PA 19380 (215) 431-9180 The sample code is in the DOS section, it is titled "Creating Multiple Processes With Re-entrant Code." -- -- Ken Farinsky - CATS - (215) 431-9421 - Commodore Business Machines uucp: ken@cbmvax.commodore.com or ...{uunet,rutgers}!cbmvax!ken bix: kfarinsky
stefanb@hathi.informatik.rwth-aachen.de (Stefan Becker) (03/07/91)
ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: >If you are really interested in this, I would recommend purchasing the >AmigaMail Volume I notebook from CATS: What books are available from CATS? Cost? Stefan -- Mail : Stefan Becker, Holsteinstrasse 9, D-5100 Aachen /// Only Phone : +49-241-505705 FIDO: 2:242/7.6 Germany /// Amiga makes Domain: stefanb@informatik.rwth-aachen.de \\\/// it possible.. Bang : ..mcvax!unido!rwthinf!stefanb \XX/ -->A3000/25<--
forgeas@swinjm.UUCP (Jean-Michel Forgeas) (03/08/91)
In article <06417.AA06417@babylon.rmt.sub.org>, Ralph Babel writes: > In article <19578@cbmvax.commodore.com>, > ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: > > > LoadSeg() needs a BPTR to a seg list, which can be faked > > like: > > > > /* From Mike Sinz AmigaMail example */ > > struct CodeHdr > > { > > ULONG SegSize; /* sizeof(struct CodeHdr) */ > > ULONG NextSeg; /* Must be NULL */ > > UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ > > APTR Function; /* a pointer to the function */ > > } > > I'd call this self-modifying code. I don't see where you find self-modifying code in the example above. All I see is data (while there is no process running on it). Effectively after CreateProc() on it this data becomes code, but there is no modification of the code after CreateProc(). -- \___/ Jean-Michel Forgeas \-/ cbmvax!cbmehq!cbmfra!swinjm!forgeas | The Software Winery -^- And, where is the universe ?
rosenber@ra.abo.fi (Robin Rosenberg INF) (03/12/91)
In article <06417.AA06417@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralph Babel) writes: >In article <19578@cbmvax.commodore.com>, >ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: >> LoadSeg() needs a BPTR to a seg list, which can be faked >> like: >> >> /* From Mike Sinz AmigaMail example */ >> struct CodeHdr >> { >> ULONG SegSize; /* sizeof(struct CodeHdr) */ >> ULONG NextSeg; /* Must be NULL */ >> UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ >> APTR Function; /* a pointer to the function */ >> } >I'd call this self-modifying code. >Ralph I have a slightly different version, that does not contain self-modifying code. Instead of patching the jump instrction, I patch data for the instruction. This code is of course not reentrant. struct FakeSeg { LONG size; BPTR next; LONG move_inst; WORD jump_inst; APTR codeptr; }; static struct FakeSeg __far FS = { 0,0, 0x207A0004, /* MOVEA.L 4(PC),A0 */ 0x4ED0, /* JMP (A0) */ 0 /* *DATA*, not code */ }; struct MsgPort *QuickCreateProc(UBYTE name,LONG pri,APTR func,LONG stacksize) { /* Now I modify the faked segment, no not the code, only the data */ FS.codeptr = func; return CreateProc(name,pri, (ULONG)&FS.next >> 2 ,stacksize); } Have fun Robin
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/12/91)
In article <ROSENBER.91Mar11193029@ra.abo.fi>, rosenber@ra.abo.fi (Robin Rosenberg INF) writes: > I have a slightly different version, that does not contain > self-modifying code. Instead of patching the jump > instrction, I patch data for the instruction. This code is > of course not reentrant. Not being reentrant is kind of ugly, of course, but I see two more potential problems: Static structures are not necessarily longword-aligned (at least with SAS/C 5.10a), and - structures usually being located in a data hunk - a future version of LoadSeg() _could_ selectively clear the code cache only for the address ranges of the code hunks just loaded, not data and bss - a useful optimization for very big caches. This is purely fictitious, of course. Ralph
bombadil@diku.dk (Kristian Nielsen) (03/12/91)
rosenber@ra.abo.fi (Robin Rosenberg INF) writes: >In article <06417.AA06417@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralph Babel) writes: >>In article <19578@cbmvax.commodore.com>, >>ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: >>> LoadSeg() needs a BPTR to a seg list, which can be faked >>> like: >>> >>> /* From Mike Sinz AmigaMail example */ >>> struct CodeHdr >>> { >>> ULONG SegSize; /* sizeof(struct CodeHdr) */ >>> ULONG NextSeg; /* Must be NULL */ >>> UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ >>> APTR Function; /* a pointer to the function */ >>> } >>I'd call this self-modifying code. >>Ralph >I have a slightly different version, that does not contain >self-modifying code. Instead of patching the jump instrction, I patch >data for the instruction. This code is of course not reentrant. Why go to all this trouble? Just use the AmigaMail example like this: void foo(void){ DoSomeThing(); } /* Static initialised data (really code). */ struct CodeHdr fooSegList={ sizeof(struct CodeHdr), NULL, 0x4EF9, (APTR)foo }; void main(void){ CreateProc(&CodeHdr>>2,...); } Since the struct CodeHdr is initialised at compiletime, this is not using self-modifying code; the code never changes after the original LoadSeg() (if LoadSeg differentiates between CODE and DATA sections, it might be nessesary to ensure that the structure is placed in the CODE section; I'm not really sure about this point). Also, it is fully reentrant (provided that one keeps a seperate structure for each function and that one does not change it, of course). Kristian.
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/13/91)
In article <1991Mar12.123403.2415@odin.diku.dk>, bombadil@diku.dk (Kristian Nielsen) writes: > /* Static initialised data (really code). */ > struct CodeHdr fooSegList={ > sizeof(struct CodeHdr), > NULL, > 0x4EF9, > (APTR)foo > }; Same problem: not necessarily longword-aligned. > (if LoadSeg differentiates between CODE and DATA sections, > it might be nessesary to ensure that the structure is > placed in the CODE section; Currently it doesn't, but you never know. Some compilers move "const" data into the code hunk. Ralph
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/13/91)
In article <19832@cbmvax.commodore.com>, mks@cbmvax.commodore.com (Michael Sinz) writes: > Have always the same startup code which gets the startup > message. In the startup message, have a function pointer > that points at the real function to run. Sounds a lot like an article of mine published in Amiga-Magazin #2/1990. :-) Here's an excerpt: ------------------------------------------------------------ struct StartupMessage { struct Message Message; LONG (*Function)(void *); void *Argument; LONG Result; }; /*** process entry point, MUST BE first function in module! ***/ static void __saveds ProcEntry(void) { struct MsgPort *mp; struct StartupMessage *sm; mp = &((struct Process *)FindTask(NULL))->pr_MsgPort; for(;;) if(WaitPort(mp) != NULL) if((sm = (struct StartupMessage *)GetMsg(mp)) != NULL) break; sm->Result = (*sm->Function)(sm->Argument); Forbid(); ReplyMsg((struct Message *)sm); } /*** code section ***/ static struct MsgPort *NewProc( struct StartupMessage *sm, LONG (*pfl)(void *), void *arg) { struct MsgPort *mp; sm->Function = pfl; sm->Argument = arg; if((mp = CreateProc("ChildProc", DEFAULT_PRI, CADDR(ProcEntry) - 1, DEFAULT_STACK)) != NULL) { PutMsg(mp, (struct Message *)sm); } return mp; } ------------------------------------------------------------ Ralph
rosenber@ra.abo.fi (Robin Rosenberg INF) (03/13/91)
In article <06533.AA06533@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralph Babel) writes: >In article <ROSENBER.91Mar11193029@ra.abo.fi>, >rosenber@ra.abo.fi (Robin Rosenberg INF) writes: >> I have a slightly different version, that does not contain >> self-modifying code. Instead of patching the jump >> instrction, I patch data for the instruction. This code is >> of course not reentrant. >Not being reentrant is kind of ugly, of course, but I see >two more potential problems: Static structures are not >necessarily longword-aligned (at least with SAS/C 5.10a), >and - structures usually being located in a data hunk - a >future version of LoadSeg() _could_ selectively clear the >code cache only for the address ranges of the code hunks >just loaded, not data and bss - a useful optimization for >very big caches. This is purely fictitious, of course. Not being reentrant only means that you have to think about where it is being used. Neither does it matter whether the structure is longword aligned or not. Word alignment is sufficient for any 680xx processor. And that is guaranteed by all Amiga compilers. It was pointed out in another posting (by Kristian Nielsen) that I doing unnecessary work. The simpler solution is to have a fake segment fully initialized at compile time, per process entry function. I think I will go with that version instead. Should be clean in any way as long as we are allowed to executed code from a data segment Robin
bombadil@diku.dk (Kristian Nielsen) (03/14/91)
rbabel@babylon.rmt.sub.org (Ralph Babel) writes: >In article <1991Mar12.123403.2415@odin.diku.dk>, >bombadil@diku.dk (Kristian Nielsen) writes: >> /* Static initialised data (really code). */ >> struct CodeHdr fooSegList={ >> sizeof(struct CodeHdr), >> NULL, >> 0x4EF9, >> (APTR)foo >> }; >Same problem: not necessarily longword-aligned. Yeah, I forgot... and I won't even try to defend myself with any talk about __align keywords or anything... >> (if LoadSeg differentiates between CODE and DATA sections, >> it might be nessesary to ensure that the structure is >> placed in the CODE section; >Currently it doesn't, but you never know. >Some compilers move "const" data into the code hunk. Yes, I thought about that, but it is only 'some'. I guess the next best way is to resort to the good old assembler: SECTION fakeseglists,CODE fakeseglist MACRO ;label,entry XDEF \1 XREF \2 CNOP 0,4 ;Align to long word. dc.l 14 ;size. \1 dc.l 0 ;pointer to next segment. jmp \2 ;Jump to entry point. ENDM fakeseglist seglist1,entry1 ;Seglist pointer for entry1(). fakeseglist seglist2,entry2 fakeseglist seglist3,entry3 END This way, the code should end up longword aligned AND in code segment. >Ralph - Kristian.
dillon@overload.Berkeley.CA.US (Matthew Dillon) (03/15/91)
In article <06533.AA06533@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralph Babel) writes: >In article <ROSENBER.91Mar11193029@ra.abo.fi>, >rosenber@ra.abo.fi (Robin Rosenberg INF) writes: > >> I have a slightly different version, that does not contain >> self-modifying code. Instead of patching the jump >> instrction, I patch data for the instruction. This code is >> of course not reentrant. > >Not being reentrant is kind of ugly, of course, but I see >two more potential problems: Static structures are not >necessarily longword-aligned (at least with SAS/C 5.10a), >and - structures usually being located in a data hunk - a >future version of LoadSeg() _could_ selectively clear the >code cache only for the address ranges of the code hunks >just loaded, not data and bss - a useful optimization for >very big caches. This is purely fictitious, of course. > >Ralph Well, actually, the very first declaration in an object module is going to be longword aligned so even if you do not have __aligned it isn't much of a problem. Also, it's easy to throw in a little assembly code to fake the seglist. Frankly, I don't see what the fuss is. You just make the program RESIDENT and RUN it twice. Under 2.0 you don't even have to use Execute() or System() -- you can use RunCommand(), and get *exactly* what you want! Also, under 2.0, you can specify a starting PC instead of a seglist when you create a new process so you don't have to deal with these dummy segments anyway! -Matt -- Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA
srwmcln@windy.dsir.govt.nz (03/15/91)
In article <06417.AA06417@babylon.rmt.sub.org>, rbabel@babylon.rmt.sub.org (Ralph Babel) writes: > In article <19578@cbmvax.commodore.com>, > ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: > >> LoadSeg() needs a BPTR to a seg list, which can be faked >> like: >> >> /* From Mike Sinz AmigaMail example */ >> struct CodeHdr >> { >> ULONG SegSize; /* sizeof(struct CodeHdr) */ >> ULONG NextSeg; /* Must be NULL */ >> UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ >> APTR Function; /* a pointer to the function */ >> } > > I'd call this self-modifying code. > > Ralph This not self modifing code, it is one piece of code CREATING another new codesegement. Such things may cause a little trouble with D and I caching, without help from the OS, but it is not one code segement modifying it's self or another preexisting code segement. Clive.
mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) (03/19/91)
In article <1991Mar14.203351.21444@Sandelman.OCUnix.On.Ca> rosenber@ra.abo.fi (Robin Rosenberg INF) writes: ... >It was pointed out in another posting (by Kristian Nielsen) that I >doing unnecessary work. The simpler solution is to have a fake segment >fully initialized at compile time, per process entry function. I think >I will go with that version instead. Should be clean in any way as >long as we are allowed to executed code from a data segment > > > Robin >-- > :!mcr!: | The postmaster never | So much mail, > Michael Richardson | resolves twice. | so little time. >HOME: mcr@sandelman.ocunix.on.ca Bell: (613) 237-5629 > Small Ottawa nodes contact me about joining ocunix.on.ca! In an attempt to repost a number of articles concerning CreateProc for Russell McOrmond's benefit, I inadvertidly may have released a number of duplicates out into the net. I made very sure to grep -v out the Message-Id: when I did it so that my software wouldn't junk them. Sorry for any confusion. (The articles may not have actually made it out into the net.) -- :!mcr!: | The postmaster never | So much mail, Michael Richardson | resolves twice. | so little time. HOME: mcr@sandelman.ocunix.on.ca Bell: (613) 237-5629 Small Ottawa nodes contact me about joining ocunix.on.ca!