d87-khd@sm.luth.se (Karl-Gunnar Hultland) (05/04/90)
I have some sort of problem with an application I'm working on. I want to have a main program which should take care of menues etc and then upon command Load and Create some new processes who will open a window on the Custom screen and execute in that window. The problem is : If I comment away the LoadSeg and CreateProc and start the program Proc.c via a different CLI it works Like a Dream. BUT if I use the code in Main.c I never get the window to open. I have verifyed with Xoper that the process exists but doesn't open the window and thus it can't exit. The question is: Is there ANYTHING I should do that I don't?? (code extracts follow .sig) Karl --- Karl Hultland,(d87-khd@sm.luth.se) University of Lulea,Sweden Egoist: a person of low taste, more interested in himself than in me. - A. Bierce ========================================================================= Main.c ========================================================================= handleMSG(n) int n; { if (segm1) UnLoadSeg(segm1); MenuOn(0); MenuOn(3); return 0; } Load(n,msg,str) int n; struct OLFMessage *msg; STRPTR str; { MenuOff(0); MenuOff(3); segm1=LoadSeg(str); proc1=CreateProc(str,0,segm1,4000); mesg1->Msg.mn_Node.ln_Type = NT_MESSAGE; mesg1->Msg.mn_Length=sizeof(struct OLFMessage); mesg1->Msg.mn_ReplyPort=OLFr; mesg1->Code=HELLO; mesg1->From=MAIN; mesg1->To=TEST; mesg1->scr=myscr; SafePutToPort( (struct Message *) mesg1,"OLF"); return 0; } ========================================================================= Proc.c ========================================================================= do { msg=WaitForMsg("OLF",HELLO,TEST); /* Wait for WELCOME message */ } while (msg==NULL); scr=msg->scr; /* Get address of screen */ TestWin.Screen=scr; win=OpenWindow(&TestWin); /* Open window on customscreen */ signalmask=1L << win->UserPort->mp_SigBit; while (!done){ /* Wait until closegadget is selected */ signals=Wait(signalmask); if (signals & signalmask) done=handleIDCMP(win); }; if (win) CloseWindow(win); if (GfxBase) CloseLibrary( (struct Library *) GfxBase); if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase); ReplyMsg( (struct Message *)msg ); }
a464@mindlink.UUCP (Bruce Dawson) (05/05/90)
> root@dialog.sub.org writes: > > Msg-ID: <1856@dialog.sub.org> > Posted: 5 May 90 08:23:45 GMT > > Org. : Dialog Software Development > Person: Christian Motz > > Now for the "dirty" way, and my question how dirty this is, and > whether or not there is any cleaner way to do it. My problem was to > start a process much like Execute(), only asynchronously. As far as I > know, AmigaDOS knows no call for something like this. I know there are > things like ArpAsyncRun(), but I would like to do it on a " stock" > Amiga (besides: I wonder if ArpAsyncRun() is so clean itself). > > Now hold on to your seats, NetPeople, just in case this is the worst > programming practice you have ever seen -- feel free to flame me, but > only if you know of a better, "legitimate" solution. > > -- > Christian Motz root@dialog.sub.org Two of your debatable assumptions can easily be made solid. These are the assumption that CreateProc() will continue to return the address of the message port, and that A0 and D0 can continue to be set by poking into the stack. Both of these problems can be solved by doing a CreateProc on a short little assembler routine which will communicate with the main program. The assembler routine tells the main program where it's task structure is (easily found with FindTask(0L)) then it loads A0 and D0 (far far easier to load A0 and D0 of your own task than somebody elses) and then it does a JSR to the code that you actually want turned into a process. That still leaves the messiness of filling out pr_CIS and pr_COS, but at least two assumptions disappear. .Bruce. -- Bruce Dawson Day job: Distinctive Software Inc. Company name: CygnusSoft Software Work hard, rock hard, eat hard, sleep hard, grow big, wear glasses if you need 'em. Webb Wilder credo.
root@dialog.sub.org (Christian Motz) (05/05/90)
In article <897@tau.sm.luth.se> d87-khd@sm.luth.se (Karl-Gunnar Hultland) writes: > >I have some sort of problem with an application I'm working on. >I want to have a main program which should take care of menues etc and >then upon command Load and Create some new processes who will open a >window on the Custom screen and execute in that window. > >The problem is : >If I comment away the LoadSeg and CreateProc and start the program >Proc.c via a different CLI it works Like a Dream. BUT if I use the >code in Main.c I never get the window to open. >I have verifyed with Xoper that the process exists but doesn't open >the window and thus it can't exit. > >The question is: Is there ANYTHING I should do that I don't?? If I judge this right from the description of the problem, you are basically trying to run an asynchronous Process using LoadSeg() and CreateProc(). I tried this, and after some time got it to work, although I am quite sure that my method is somewhat illegal. But more about that later on. When a program is started, the C startup code checks to see whether it is started from the CLI (or via Execute() for that matter) or from Workbench. This is done by checking the pr_CLI member in the process structure. If it is NULL, the code assumes it has been started from Workbench and therefore is waiting for a Workbench- startup- message. I suppose that this is the problem you' re having -- the main()-function never gets called although a process has been created, right? Obviously the C startup code is waiting for the Workbench message it never gets. The "clean" way to circumvent this, I think, is to not use the C startup code, i.e. _main(). This of course can be painful if you like to use stdio stuff, but it works. Now for the "dirty" way, and my question how dirty this is, and whether or not there is any cleaner way to do it. My problem was to start a process much like Execute(), only asynchronously. As far as I know, AmigaDOS knows no call for something like this. I know there are things like ArpAsyncRun(), but I would like to do it on a " stock" Amiga (besides: I wonder if ArpAsyncRun() is so clean itself). Now hold on to your seats, NetPeople, just in case this is the worst programming practice you have ever seen -- feel free to flame me, but only if you know of a better, "legitimate" solution. Code fragment follows ... /* ** We LoadSeg() the compress code at this point if it is not already ** loaded. With this we can achieve an additional performance increase ** by LoadSeg()'ing it just once at the beginning, then reusing it over ** and over again and UnLoadSeg()'ing it when we're done. This saves ** valuable time loading the code in memory. */ if (seglist == 0L) { seglist = LoadSeg(comp); } /* ** Now it is time to open the files to be used as compress's standard ** in- and output. We have to seek to position 12 of the input file, ** since it begins with "#! cunbatch\n" before the compressed batch ** file. Standard output is, of course, the pipe. We open them here ** because it would mess with the Forbid()-call if we would do it ** later on, since I/O re-enables Multitasking, thus effectively ** voiding any setup we make for the new process. */ if (seglist != 0L) { if ((cis = Open(in, MODE_OLDFILE)) != NULL) { Seek(cis, 12L, -1L); if ((cos = Open(pn, MODE_NEWFILE)) != NULL) { /* ** Here comes the tricky part. We have to create the process from the ** loaded code and hand the command line arguments to it. For this we ** disable multitasking while we set up the process environment of the ** new process, to keep the operating system from messing with the data. */ Forbid(); pid = CreateProc("compress", 0L, seglist, 4000L); /* ** Guess how long it took me 'til I found out that CreateProc() returns ** the address of the process's MessagePort, not its process structure? ** Anyway, the MessagePort is the second member of the structure, the ** first being the Task structure. Thus the process structure address ** is pid-sizeof(struct Task). Voila, you have the process address, ** allowing you to manipulate it any way you want to. This of course is ** an assumption, and thus bad programming practice. But what else are ** you supposed to do under this operating system? */ pr = (struct Process *)(pid - (long)sizeof(struct Task)); pr->pr_CIS = (BPTR)cis; pr->pr_COS = (BPTR)cos; cli->cli_CommandName = (long)cmd >> 2L; pr->pr_CLI = (long)cli >> 2L; /* ** Have you ever thought about how command line arguments are passed ** under AmigaDOS? No? Well, the read this and learn something :-). ** A newly created process gets the address of the command line ** parameters in the processor register A0, and its length in the ** register D0. This is all very fine and dandy, and makes for nice ** and easy startup code. But if you try to create a process and hand ** it some parameters, it is virtually impossible to set these registers ** in an operating system-friendly fashion. The only way I have found is ** by determining the addresses of these registers in the initial ** register set on the process stack, and writing to them the desired ** values. This of course is really messy and ugly, so you may not want ** to look at it. */ t = (long)(pr->pr_Task.tc_SPUpper); d = t - 68L; a = d + 32L; a0 = (char **)a; d0 = (long *)d; *a0 = opt; *d0 = (long)strlen(opt); /* ** Everything is set up now, so we can allow the operating system to ** resume multitasking, thus allowing the new process to be scheduled ** for execution. We don't care what happens to it (actually we have ** no other choice), so we continue by calling unbatch, feeding it the ** pipe as input file. */ Permit(); End of code fragment ... How long can you get thrown in jail for doing something like that? But seriously, how about a better way? Any hint would be appreciated. The above code works, no doubt about it, but after writing it I felt like I had just emerged from a pile of sh**, because of all the messy things I did and assumptions I made ... -- Christian Motz root@dialog.sub.org
peter@sugar.hackercorp.com (Peter da Silva) (05/06/90)
In article <1856@dialog.sub.org> root@dialog.sub.org (Christian Motz) writes about C startup code waiting for a workbench message. > The "clean" way to circumvent this, I think, is to not use the C > startup code, i.e. _main(). This of course can be painful if you like > to use stdio stuff, but it works. No, the clean way to do this is to send a workbench message. I published a complete package for starting programs in this environment, under the name "launch". Look for it at your nearest archive site. If you don't do something like this the process will never get cleaned up after, and you'll eat memory every time you run it. Then you can add extra stuff you want to feed the program (like file handles) after the message. This is pretty much how RogueStart works (which is something else you should look into). > How long can you get thrown in jail for doing something like that? How long can you tread water? -- _--_|\ Peter da Silva <peter@sugar.hackercorp.com>. / \ \_.--._/ I haven't lost my mind, it's backed up on tape somewhere! v "Have you hugged your wolf today?" `-_-'
peter@sugar.hackercorp.com (Peter da Silva) (05/06/90)
In article <1677@mindlink.UUCP> a464@mindlink.UUCP (Bruce Dawson) writes: > These are the > assumption that CreateProc() will continue to return the address of the > message port Since it's more or less documented as doing this, and since changing this would break so much working code, this is pretty safe. -- _--_|\ Peter da Silva <peter@sugar.hackercorp.com>. / \ \_.--._/ I haven't lost my mind, it's backed up on tape somewhere! v "Have you hugged your wolf today?" `-_-'
root@dialog.sub.org (Christian Motz) (05/07/90)
In article <5662@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: > > [My own ramblings about CreatProc()'ing a process deleted] > >No, the clean way to do this is to send a workbench message. I published a >complete package for starting programs in this environment, under the name >"launch". Look for it at your nearest archive site. Yes, but can it start *UNMODIFIED* CLI programs? They won't be running properly when not started from CLI, and I can't imagine I would be able to set pr_CIS and pr_COS in anyway. As I said, The problem in my case is to create sort of an asynchronous Execute(). This includes passing command line arguments in the standard fashion and allowing for pr_CIS and pr_COS to be set. >If you don't do something like this the process will never get cleaned up >after, and you'll eat memory every time you run it. Well, actually the code I posted works just fine, even in the sense that it doesn't even lose one byte of memory. Obviously the process gets cleaned up perfectly, since I seem to have fooled the OS in believing that it is a standard CLI process. Strange but true. >Then you can add extra stuff you want to feed the program (like file handles) >after the message. This is pretty much how RogueStart works (which is something >else you should look into). As I said, this is something I cannot do, since the programs to be started are usually standard CLI programs, often to the effect that they can't or shouldn't be modified. Arrgh! I want fork()! -- Christian Motz root@dialog.sub.org
jmeissen@oregon.oacis.org (John Meissen) (05/08/90)
In article <1677@mindlink.UUCP> a464@mindlink.UUCP (Bruce Dawson) writes: >> root@dialog.sub.org writes: >> whether or not there is any cleaner way to do it. My problem was to >> start a process much like Execute(), only asynchronously. As far as I [...] >of these problems can be solved by doing a CreateProc on a short little >assembler routine which will communicate with the main program. The assembler This is basically what I did when I wrote the fork() implementation for the Lattice compiler. Given this approach you have a lot of flexibility. I attached an assembler stub to the LoadSeg'd code that waited for a startup message from the parent process. This message contained the argument string and miscellaneous stuff I don't remember any more. In addition, the reply port was used for returning the exit status of the child process, making it possible to wait on it and unload it. That's one thing you need to remember, that LoadSeg'd code won't automatically get UnLoaded, you have to either do it manually or attach the SegList to the task structure so the system will do it for you. -- John Meissen ............................... Oregon Advanced Computing Institute jmeissen@oacis.org (Internet) | "That's the remarkable thing about life; ..!sequent!oacis!jmeissen (UUCP) | things are never so bad that they can't jmeissen (BIX) | get worse." - Calvin & Hobbes
jmeissen@oregon.oacis.org (John Meissen) (05/08/90)
In article <5662@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: >No, the clean way to do this is to send a workbench message. I published a This only works for programs that are written to support being launched from Workbench. If the program expects a CLI type command line with arguments and switches, then this won't work. -- John Meissen ............................... Oregon Advanced Computing Institute jmeissen@oacis.org (Internet) | "That's the remarkable thing about life; ..!sequent!oacis!jmeissen (UUCP) | things are never so bad that they can't jmeissen (BIX) | get worse." - Calvin & Hobbes
peter@sugar.hackercorp.com (Peter da Silva) (05/09/90)
In article <482@oregon.oacis.org> jmeissen@oregon.oacis.org (John Meissen) writes: > In article <5662@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: > >No, the clean way to do this is to send a workbench message. I published a > This only works for programs that are written to support being launched from > Workbench. ALL programs should be written to support being launched from either the Workbench or the CLI, so this translates to "this only works for non-buggy programs". Which is fine by me. The CLI startup environment is a crock anyway. And, of course, if you're writing the launchee as well as the launcher you can go wild... -- _--_|\ Peter da Silva <peter@sugar.hackercorp.com>. / \ \_.--._/ I haven't lost my mind, it's backed up on tape somewhere! v "Have you hugged your wolf today?" `-_-'
panon@cheddar.cc.ubc.ca (Paul-Andre Panon) (05/09/90)
In article <1860@dialog.sub.org> root@dialog.sub.org (Christian Motz) writes: >>Then you can add extra stuff you want to feed the program (like file handles) >>after the message. This is pretty much how RogueStart works (which is something >>else you should look into). > >As I said, this is something I cannot do, since the programs to be >started are usually standard CLI programs, often to the effect that >they can't or shouldn't be modified. Arrgh! I want fork()! ^^^^^^^ > >-- >Christian Motz root@dialog.sub.org I was going to say "couldn't you fake a fork()-Execute()?". What I had in mind (based on someone else's (device driver?) code from long ago) was: - Have a procedure in your program which is just specialized code that waits for a(n extended) WorkbenchStartup message, takes the required info from the message, and calls Execute() with it. - then, find your SegList and follow down it until you find the address of said procedure. - use that as the SegList for a call to CreateProcess(). - the child process will then Execute() the program with the parameters you gave it. - make sure your parent doesn't exit before the child does so that you can cleanup the child's resources and so that the pseudoforked section of the code doesn't get deallocated. You can separate the child code by detaching it from your SegList if you linked it so it would be last on the main SegList when loaded, and thus the parent program can exit without cleaning up for the child or the child getting the rug pulled out from under it, but you will lose the associated memory (nobody will be around to clean it up) so you should only do it if you want the code to stay around forever (for background demons and so forth - in which case you should probably have been able to use CreateProcess() directly instead of using Execute()). If you don't mind having to wait for the child to finish eventually but just want to do something else NOW, then this should do what you want. And it's likely to be more robust than your current method. Your ugly hack :-) :-) seems like the only way to spawn CLI processes and not have to worry about them later though and would probably be what you'd have to do if you were writing a shell for instance (actually I was wondering how to do that so thanks for the hint - I hope I never need it). -- Paul-Andre_Panon@staff.ucs.ubc.ca or USERPAP1@UBCMTSG or Paul-Andre_Panon@undergrad.cs.ubc.ca or USERPAP1@mtsg.ubc.ca Looking for a .signature? "We've already got one. It is ver-ry ni-sce!"
jmeissen@oregon.oacis.org (John Meissen) (05/09/90)
In article <1860@dialog.sub.org> root@dialog.sub.org (Christian Motz) writes: >As I said, this is something I cannot do, since the programs to be >started are usually standard CLI programs, often to the effect that >they can't or shouldn't be modified. Arrgh! I want fork()! Have you checked the manual? Both C compilers have something similar to fork(). Manx, I believe, has forkexec(), and Lattice has forkl() and forkv(). The Lattice version wouldn't work for BCPL code (C= wouldn't give us any help on how to setup a BCPL process, and Metacomco wouldn't talk to us), but if you are fork'ing something you wrote then it's no problem. Of course, John Toebes may have re-worked the Lattice version to use Execute(), so it may work generically now. -- John Meissen ............................... Oregon Advanced Computing Institute jmeissen@oacis.org (Internet) | "That's the remarkable thing about life; ..!sequent!oacis!jmeissen (UUCP) | things are never so bad that they can't jmeissen (BIX) | get worse." - Calvin & Hobbes
d87-khd@sm.luth.se (Karl-Gunnar Hultland) (05/09/90)
In article <5674@sugar.hackercorp.com> peter@sugar.hackercorp.com (Peter da Silva) writes: > >ALL programs should be written to support being launched from either the >Workbench or the CLI, so this translates to "this only works for non-buggy >programs". Which is fine by me. The CLI startup environment is a crock >anyway. In my case the MAIN program supports being launched either from WB or CLI which isn't very difficult 'cause I dont use stdio or cli-arguments, but the sub-programs being "launched" from the MAIN (and only from the main) shouldn't have to bother about WB or CLI. All I want to is to start them, send them a message containing the address of the costomscreen I use, and when they exit let the MAIN program do the unloading. > >And, of course, if you're writing the launchee as well as the launcher you can >go wild... In my case i could go wild, but since your launch package does,almost, all the work I'll use it. THe irritating part is that I'll have to allocate and send an extra message to the child, with the address to the screen. But this is a minor nuisance with which I'll have to live. Thanks anyway for you launch program. Karl ps. That pic. in your .sig is that to be Australia? --- Karl Hultland,(d87-khd@sm.luth.se) University of Lulea,Sweden Egoist: a person of low taste, more interested in himself than in me. - A. Bierce
peter@sugar.hackercorp.com (Peter da Silva) (05/10/90)
In article <908@tau.sm.luth.se> Karl-Gunnar Hultland <d87-khd@tau.luth.se> writes: > In my case the MAIN program supports being launched either from WB or CLI > which isn't very difficult 'cause I dont use stdio or cli-arguments, but > the sub-programs being "launched" from the MAIN (and only from the main) > shouldn't have to bother about WB or CLI. All I want to is to start them, > send them a message containing the address of the costomscreen I use, > and when they exit let the MAIN program do the unloading. Sounds good. I'd recommend keeping all the WBstartup stuff anyway, and in main() look for a magic word *beyond* the normal WBStartup message. That way if the child programs get started up under another environment by accident they won't kill the system. > In my case i could go wild, but since your launch package does,almost, > all the work I'll use it. THe irritating part is that I'll have to allocate > and send an extra message to the child, with the address to the screen. Just modify my launch program to send an extra two LONGs, one being a magic word to indicate it's a "special environment" launch (like, if the first word after WBStartup is "0xFEEDFACE"), and the other a pointer to your magic stuff. One message, no problems. > Thanks anyway for you launch program. Welcome. > ps. That pic. in your .sig is that to be Australia? Yep, it be Oz. -- _--_|\ Peter da Silva <peter@sugar.hackercorp.com>. / \ \_.--._/ I haven't lost my mind, it's backed up on tape somewhere! v "Have you hugged your wolf today?" `-_-'