[comp.sys.amiga] Posting of CSNEWS 'AMIGA' discussion, entry #193.

STEVEG@MAINE.Bitnet.UUCP (05/11/87)

tasks spawned under program control.  The documented
call AddTask() in the RKM v.1 does not work properly
on my machine.
    As a matter of fact, CreateProc() doesn't work either.
In the case of the AddTask() call, I get a Guru alert.  In
the case of the CreateProc() call, aboslutely nothing happens.
    After the CreateProc() goes to completion with a non-zero
return, the associated task state is 8, not defined in the RKM.
Anybody know what state this is?
    Is or has anybody had any luck using either of these two
functions?  Does anyone know for a fact that the RKM is in
error?  (I got my set of manuals way back when Commodore first
released them, not the later Addison-Wesley publications)
    Also, does LoadSeg return the address of the first instruction
of the loaded program, or does it return something else?  If it
returns something else, how do you get the first instruction from
that.
    Lastly, an observation -- the call FindTask() returns a pointer
to a struct Process.  The first element of a Process is a struct
Task, but the Process information is all there for you to look at.
     
                                Mitch
     

dillon@CORY.BERKELEY.EDU.UUCP (05/12/87)

>tasks spawned under program control.  The documented
>call AddTask() in the RKM v.1 does not work properly
>on my machine.
>    As a matter of fact, CreateProc() doesn't work either.
>	...

	LoadSeg() returns an (ugg) BPTR, which means you have to shift
left by two.  You also have to add 4 since there is a link to the next
segment before the code starts.

	entrypoint = (segment<<2)+4

	AddTask() takes a preallocated and preinitialized task structure,
the starting PC (the actual entrypoint), and the ending PC (which is what is
pushed on the stack so if your top level code exits, the ending PC is
called.  if the ending PC is NULL, then the system will use it's own
ending PC causing the task to be deleted on exit.

	CreateProc() takes a segment, so if you want to CreateProc() 
something other than the segment returned by LoadSeg() you will need to
'fake' a segmen in assembly lange.  I.E. CreateProc() takes a BPTR.

-------------
	FindTask() is spec'd to return the address of a task.  Since a 
process has a task as its first entry, this also points to a process...
BUT ONLY IF THE TASK IS ACTUALLY A PROCESS.  Otherwise, casting the 
return pointer to a process is meaningless.  You can look at the node
type in the task/process structure to determine whether it is a task or
process.
--------------

	DON'T EXPECT TO BE ABLE TO SIMPLY LOADSEG() AND CREATEPROC() ANY
ARBITRARY EXECUTABLE.  It doesn't work.  CreateProc() doesn't setup all
the fields in the process structure neccessary for most executables to run.
Additionaly, you need to preset certain registers if the executable is a
BCPL program.   So far, nobody I know has been able to use CreateProc() to
successfully run an arbitrary executable as a separate process.  Both I
in my shell and Aztec in their fexec() use the calling process's process
structure and doesn't even create a new process.  

	The only alternative is to Execute() a RUN command
to run the executable.  This works fine, but unfortunetly you can't get
the return value when the thing exits or even know when it exits, and you
can setup input redirection.

	Note that if you successfully AddTask() or CreateProc() a code
segment which is actually part of the parent process, that code segment 
must be very careful in what it does so it stays within the bounds of being 
a separate process.  For instance, you cannot make any stdio calls from that
code segment since it will interfere with stdio calls the parent is making.

	There is another call, CreateTask(), which I believe exists in the
1.2 Amiga library.  This call does all the work required to setup a Task
structure and then calls AddTask().  It has the same parameters as 
CreateProc(), but creates a Task instead.  If you have the source to MWB,
you might want to take a look at how it spawns its resident portion.  If
not, mail me and I'll send you the source.

					-Matt
	

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner CATS) (05/15/87)

In article <48CSNEWS@MAINE> CSNEWS@MAINE.BITNET (CSNEWS CSBB Processor) writes:
>[]
>The documented call AddTask() in the RKM v.1 does not work properly
>on my machine.

   AddTask() requires a bit of setup.  I suggest using CreateTask() or
at least looking at the CreateTask() source in the RKM (appendix D in
A-W Exec manual or appendix after .i's in our 1.1 RKM Vol. II).
In addition, if you are using Manx, you are going to need some inline
assembler to fix the registers.

>    As a matter of fact, CreateProc() doesn't work either.
>In the case of the AddTask() call, I get a Guru alert.  In
>the case of the CreateProc() call, aboslutely nothing happens.

   CreateProc() requires even more setup.  For instance, if you are
CreateProc'ing inline code rather than LoadSeg'd code, you must provide
a dummy seglist.  If you have LoadSeg'd a standalone program with normal
startup code, you must create a port, build a WBenchMsg, and send it
to the new process whose startup code is Wait'ing for that message.

>    After the CreateProc() goes to completion with a non-zero
>return, the associated task state is 8, not defined in the RKM.
>Anybody know what state this is?

   Got me.  I could look at the source, but I don't have time.

>    Is or has anybody had any luck using either of these two
>functions?  Does anyone know for a fact that the RKM is in
>error?  (I got my set of manuals way back when Commodore first
>released them, not the later Addison-Wesley publications)

   I've used CreateTask().  I've seen CreateProc() used.  Again,
see the Appendix.  And the example at the end of this message.

>    Also, does LoadSeg return the address of the first instruction
>of the loaded program, or does it return something else?  If it
>returns something else, how do you get the first instruction from
>that.

   No.  LoadSeg returns a BPTR to the initial Segment (a longword Bpointing
to the next segment).  Multiply the BPTE by 4 (or shift left twice) then
add 4.  Now it is a C pointer to the first instruction.

>    Lastly, an observation -- the call FindTask() returns a pointer
>to a struct Process.  The first element of a Process is a struct
>Task, but the Process information is all there for you to look at.

   This is only true for Processes.  If what you find is just a Task
then the additional Process info is not there.
----------------------------------------------------------------------

Here's an example using CreateTask.  Phil Lindsay helped me straighten
out the conditional inline assembler code that I added for Manx users.
It has been tested with Lattice and Manx.

----------------------------------------------------------------------

/*
 * Task.c - a cheap sub-task example by cs
 *   Cheap =  shared data for communication rather than MsgPorts
 *   If using Aztec, #define AZTEC_C
 */

#include <exec/types.h>
#include <exec/tasks.h>

extern VOID subTaskRtn();

struct Task *CreateTask(), *subTaskPtr = 0L;
char *subTaskName = "SubTask";

/* Data shared by main and subTaskRtn */
ULONG  GfxBase = 0L;
ULONG  Counter = 0L;
LONG   PrepareToDie;

/* If using Aztec, #define AZTEC_C 
 *
 * Note: Aztec C v3.4a has built in functions that do the following
 *  for you: geta4() and sava4().
 */

#ifdef AZTEC_C
#asm
		cseg
        public  _a4sav
_a4sav
		lea.l	_a4tmp,a0
        move.l  a4,(a0)
        rts

        public  _a4get
_a4get
        lea.l   _a4tmp,a0
        move.l  (a0),a4
        rts

		public  _a4tmp
	
_a4tmp   dc.l    0
        
#endasm
#endif


main()
   {
   int k;
   ULONG ct;

   if(!(GfxBase=OpenLibrary("graphics.library",0)))
      cleanexit("Can't open graphics.library");

   PrepareToDie = FALSE;

#ifdef AZTEC_C
   a4sav();
#endif

   subTaskPtr = CreateTask(subTaskName,0,subTaskRtn,2000);
   if (!subTaskPtr)  cleanexit("Can't create subTask");

   for (k=0; k<10; k++)
      {
      Delay(50);  /* main is a process and can call Delay() */
      ct = Counter;
      printf("Counter = %ld\n",ct);
      }

   cleanup();
   }

cleanexit(s)
char *s;
   {
   if(*s)  printf("%s\n",s);
   cleanup();
   exit(0);
   }

cleanup()
   {
   if(subTaskPtr)
      {
      PrepareToDie = TRUE;
      while(PrepareToDie);
      DeleteTask(subTaskPtr);
      }
   if(GfxBase)  CloseLibrary(GfxBase);
   }


/* subTaskRtn increments Counter every 1/60 second */
VOID subTaskRtn()
   {
#ifdef AZTEC_C
   a4get();
#endif

   while(!PrepareToDie)
      {
      WaitTOF();
      Counter++;
      }
   PrepareToDie = FALSE;  /* Signal ready to die */
   Wait(0L);              /* Wait while ax falls */
   }




-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

dykimber@phoenix.UUCP (05/15/87)

In article <1875@cbmvax.cbmvax.cbm.UUCP> carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) writes:
>In article <48CSNEWS@MAINE> CSNEWS@MAINE.BITNET (CSNEWS CSBB Processor) writes:
>>The documented call AddTask() in the RKM v.1 does not work properly
>>on my machine.
>   AddTask() requires a bit of setup.  I suggest using CreateTask() or
>at least looking at the CreateTask() source in the RKM (appendix D in

I don't think CreateTask() is significantly easier to use than AddTask().
Hope I'm not saying anything blatantly stupid here, but I had the same
problem using AddTask with Manx until I decided to cast certain constant
arguments as long.
                                                   -Dan

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner CATS) (05/18/87)

In article <1875@cbmvax.cbmvax.cbm.UUCP> carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) writes:
>----------------------------------------------------------------------
>Here's an example using CreateTask.  Phil Lindsay helped me straighten
>out the conditional inline assembler code that I added for Manx users.
>It has been tested with Lattice and Manx.
>----------------------------------------------------------------------

   Forgot to tell you - If you are using Lattice, you must use the -v
flag on LC2 to disable Lattice's insertion of stack-checking code.
That code will generate an alert if you have inline code which runs
as a separate task, process, handler, etc.

   If you are using Manx, compile long (-l ?) and link with the 32-bit
library.  With a bit of work on the example, this might not be necessary.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=