[comp.sys.amiga.tech] Launching new Tasks in C

dpvc@ur-tut (Davide P. Cervone) (07/07/88)

In article <11752@agate.BERKELEY.EDU> pete@violet.berkeley.edu (Pete Goodeve) writes:
>  There's a major problem with child tasks in that their code is normally
>  loaded as part of the main program, so you don't have much flexibility to
>  change things at load time or later.  On the other hand, if for some
>  reason you wanted to invoke one module process from inside another, this
>  is pretty easy: simplest is to use the AmigaDOS call
>
>         Execute("run module")
>
>  (You would have to use "run" so you would come back to your invoking
>  module immediately.)  You might LoadSeg() and CreateProc() instead, but I
>  don't see much advantage in that.

Well, I can think of a couple reasons why LoadSeg() and CreateProc() might
be better:

First, with Execute(), you never know whether the process actually was created.
For instance, suppose the program "module" was not found, or there was
insufficient memory, or some such thing.  You'd never know, and would go 
on with your own execution expecting it to be there.  You might find out later
when you tried to send it messages that it was not registered.

Second, how can you tell when the other process is ready to run?  You could 
wait for it to send you a message, but if it was never loaded, you'll hang
waiting for a messag ehtat will never come.  You could set up time-out
conditions, but that's a lot of work for what should be a simple operation.

(I must admit that I have not spent the time I should reading the PPIPC
and OOIPC discussion, so I don't know whether you have a solution for this
kind of problem built into the IPC protocols).

Finally, once the code is loaded, you have control of it before you call
CreateProc.  You can use the pointer to the laoded code to initialize
variables, call sections of code, etc., before starting the child process.
I use this technique in wIconify and vScreen to reduce the size of the
child process.  All the library opening, error checking, screen and window
lookups, and other one-time-only work is done in the loading program, not the
child program.  Of course, this means the child program can not be run on
its own as a separate command, too.

>                                            -- Pete --

Davide P. Cervone
dpvc@tut.cc.rochester.edu
dpvc@ur-tut.UUCP
DPVC@UORDBV.BITNET

pete@violet.berkeley.edu (Pete Goodeve) (07/11/88)

In article <2261@ur-tut.UUCP> dpvc@tut.cc.rochester.edu.UUCP (Davide P. Cervone) writes:
>
>Well, I can think of a couple reasons why LoadSeg() and CreateProc() might
>be better:
>
>First, with Execute(), you never know whether the process actually was created.
>For instance, suppose the program "module" was not found, or there was
>insufficient memory, or some such thing.  You'd never know, and would go 
>on with your own execution expecting it to be there.  You might find out later
>when you tried to send it messages that it was not registered.

True, but this is the sort of thing that IPC has to handle as a matter of
course.  The sender has to expect that an attempt to send a message may
fail; it'll be informed of this and will have to take whatever action it thinks
necessary.
(Actually Execute() DOES return a success code, though I have to confess
I'm not sure what'd happen if the RUN command failed -- whether it would
fail the execute too, or not.)

>
>Second, how can you tell when the other process is ready to run?  You could 
>wait for it to send you a message, but if it was never loaded, you'll hang
>waiting for a messag ehtat will never come.  You could set up time-out
>conditions, but that's a lot of work for what should be a simple operation.

Same thing, basically.  You shouldn't actually care whether a process is
running until you want to send it something; you can always 'ping' it if
you need to know sooner.

>
>Finally, once the code is loaded, you have control of it before you call
>CreateProc.  [........]

I hope people won't write modules to run under IPC this way.  My feeling
is that they should be self contained, to be started up like any other program,
without special conditions or considerations.  If you want a module to
change its run-time state -- send it a message to do so.  Closely linked
processes and tasks like you're suggesting are fine for lots of things,
but the idea of IPC I think is to decouple things so that we can mix and
match modules more easily.

					-- Pete --

peter@sugar.UUCP (Peter da Silva) (07/12/88)

One advantage to launching your own tasks with CreateProcess is that you can
run them under a Workbench environment... which is much beter defined than the
CLI environment (for example, you don't have to puzzle out structures from
the AmigaDOS manual). And everyone writes code so it runs in both, don't
they? (sigh... please, folks, write code so it runs in both)
-- 
-- `-_-' Peter (have you hugged your wolf today?) da Silva.
--   U   Mail to ...!uunet!sugar!peter, flames to alt.dev.null.
-- "Running OS/2 on a '386 is like pulling your camper with an Indy car"

keithd@cadovax.UUCP (Keith Doyle) (07/14/88)

In article <11752@agate.BERKELEY.EDU> pete@violet.berkeley.edu (Pete Goodeve) writes:
>On the other hand, if for some
>  reason you wanted to invoke one module process from inside another, this
>  is pretty easy: simplest is to use the AmigaDOS call
>
>         Execute("run module")
>
>  (You would have to use "run" so you would come back to your invoking
>  module immediately.)  You might LoadSeg() and CreateProc() instead, but I
>  don't see much advantage in that.

Both Execute and LoadSeg()/CreateProc() have big problems
because they lead to lots of situations that confuse the hell out
of novice users.  You have to do a Execute("run name:module",0,0); because
Execute("run module",0,0); is equivalent to Execute("run df0:module",0,0); 
or maybe sys:module or something that bears no resemblance to what you are
really trying to do.  If you *do* do an Execute("run name:module",0,0); 
then either the novice can't boot off of *his* vanilla workbench disk 
because the assign name: doesn't get done, or you have to name the disk 
"name" and if you do that, the novice who forgets after backing up to edit 
the "copy of " out of the name, thinks the disk is copy protected because 
it keeps popping up requesters saying "please insert volume 'name' in 
any drive".  You'd be surprised how many novices I've talked to who did 
edit "copy of" out of the name, but didn't catch the space between "of" 
and "name".  It looks like it's the correct name, but AmigaDos doesn't 
treat them the same.
 
If you use LoadSeg, you can specify a file without full path name, relative
to the current directory which should be the one the original icon was
clicked on.  As long as all paths are relative to that directory, no
assigning or disk-name assumptions have to be made.

The problem with LoadSeg though, is if "module" itself want's to open files
relative to the directory it is in, unless you can feed to the new
CreateProc()'ed process your current directory, it won't work.  I haven't
yet checked to see if you can feed a created process it's current directory.

I'm thinking the only real way to make this all work with a minimum of
pain to the novice user, is for the original program to use successive
ParentDir()'s to construct its full path name, build and Execute() an
'Assign here: currentdirpath' command and then have everyone use here: to
find associated programs and files.  Kludgy, but it works.

What I'd like to be able to do (if it worked) is this:

	1. boot a vanilla workbench, no custom Assigns in startup-sequence
	   required.
	2. put application disk in df1: or df2: or ??(and disk can be 
	   named anything)
	3. click on drawer icon on application disk to open drawer named 
	   "appl" which contains subdirectory "stuff".
	4. click on application icon in drawer "appl"
	5. application does an Execute("run stuff/subpart",0,0);
					 ^^^^^^ note relative to application's
						current dir, "appl"
	6. "subpart" program does an Open("datafile",...).  Where datafile
	   is a relative reference (either to "appl" or "stuff", I could work
	   within either constraint).
	7. All of this stuff will still work flawlessly if you copy the entire
	   application disk into a subdirectory on a hard disk.

Unfortunately, this won't work as step 5 fails with a nonexistant 
command error reported on the CLI.  This would work if run could find
the command in the Executing program's current directory.  Makes me wonder
if a substitute RUN command could be created that would fix the problem.

And you can't do an Execute("run :appl/stuff/subpart",0,0);, as that will
violate condition 7.

If I use the technique I described above constructing an Assign here:
command, and the references in 1-7 above become here:stuff/subpart etc.
it will work, and only makes the assumption that the Assign command is
available.  Kinda hate hardcoding Assign commands in programs,
but nothing else seems to work, unless I can feed CreateProc it's
current directory somehow.  I still end up having to ParentDir it up
the tree to find out what the complete current directory path is.

If anyone can think of another method of meeting the 1-7 criteria
above, I'd be glad to hear it.

BTW, this also touches on a reason I have a big problem using anybodies
*.library for anything useful, as novices don't have the foggiest notion on 
how to install them.  An auto-install program has the problem that the 
vanilla workbench is too full, requiring something to be deleted.

Keith Doyle
#  {ucbvax,decvax}!trwrb!cadovax!keithd  Contel Business Systems 213-323-8170

peter@sugar.UUCP (Peter da Silva) (07/15/88)

In article <2148@cadovax.UUCP>, keithd@cadovax.UUCP writes:
> The problem with LoadSeg though, is if "module" itself want's to open files
> relative to the directory it is in, unless you can feed to the new
> CreateProc()'ed process your current directory, it won't work.  I haven't
> yet checked to see if you can feed a created process it's current directory.

If you send the created process a standard workbench startup message, it will
get its current directory from there (assuming it's been set up right). This
means you have to hang around until the process dies (see my "click" sample
program, published in comp.sources.amiga, or I can send you a copy). There is
a way around this, though: write a daemon that just opens up a named port (say,
"WBCleanup"), and cleans up WBStartup messages sent to this port (there is
enough info in (struct WBStartup) to do this... again, see "click"). Supply
this port as the reply port of the WBStartup message. The daemon will happily
gobble the messages up and leave you free to exit.

You *do* need to be able to run the daemon, but it doesn't have to have any
standard startup code, since it never exits. So you just look for your named
port. If it's not there, LoadSeg and CreateProc the daemon and sleep a little.
Then look for the port again.

> If anyone can think of another method of meeting the 1-7 criteria
> above, I'd be glad to hear it.

See above.

> BTW, this also touches on a reason I have a big problem using anybodies
> *.library for anything useful, as novices don't have the foggiest notion on 
> how to install them.  An auto-install program has the problem that the 
> vanilla workbench is too full, requiring something to be deleted.

It'd be nice if you could specify a complete path to OpenLibrary. Can you?
-- 
-- `-_-' Peter (have you hugged your wolf today?) da Silva.
--   U   Mail to ...!uunet!sugar!peter, flames to alt.dev.null.
-- "Running OS/2 on a '386 is like pulling your camper with an Indy car"