[comp.sys.amiga.programmer] Help!

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!