From: pottier@clipper.ens.fr (Francois Pottier) Subject: csmp-digest-v3-064 Date: Sat, 8 Oct 1994 14:49:41 +0100 (MET) C.S.M.P. Digest Sat, 08 Oct 94 Volume 3 : Issue 64 Today's Topics: Help!! argc, argv on Macintosh How to Check if drivers are open Is it possible to notify another mac? Memory moving and Inits Self-disposing notification crashes [CWWWW] PowerPlant Tour document available The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier (pottier@clipper.ens.fr). The digest is a collection of article threads from the internet newsgroup comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi- regularly and want an archive of the discussions. If you don't know what a newsgroup is, you probably don't have access to it. Ask your systems administrator(s) for details. If you don't have access to news, you may still be able to post messages to the group by using a mail server like anon.penet.fi (mail help@anon.penet.fi for more information). Each issue of the digest contains one or more sets of articles (called threads), with each set corresponding to a 'discussion' of a particular subject. The articles are not edited; all articles included in this digest are in their original posted form (as received by our news server at nef.ens.fr). Article threads are not added to the digest until the last article added to the thread is at least two weeks old (this is to ensure that the thread is dead before adding it to the digest). Article threads that consist of only one message are generally not included in the digest. The digest is officially distributed by two means, by email and ftp. If you want to receive the digest by mail, send email to listserv@ens.fr with no subject and one of the following commands as body: help Sends you a summary of commands subscribe csmp-digest Your Name Adds you to the mailing list signoff csmp-digest Removes you from the list Once you have subscribed, you will automatically receive each new issue as it is created. The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest. Questions related to the ftp site should be directed to scott.silver@dartmouth.edu. Currently no previous volumes of the CSMP digest are available there. Also, the digests are available to WAIS users. To search back issues with WAIS, use comp.sys.mac.programmer.src. With Mosaic, use http://www.wais.com/wais-dbs/comp.sys.mac.programmer.html. ------------------------------------------------------- >From victor chong Subject: Help!! argc, argv on Macintosh Date: 22 Sep 1994 21:19:15 GMT Organization: UT Austin Hi, I was wondering if someone could enlighten me concerning the usage of argv and argc when programming on the Macintosh. I'm using Symantec C++. Does the Mac allows this kind of communication with the OS or is there another method. Any kind of help will be much welcome. Thank you very much. victor victorc@sleepy.cc.utexas.edu +++++++++++++++++++++++++++ >From Eric.M.Kidd@dartmouth.edu (Eric M. Kidd) Date: 23 Sep 1994 00:11:36 GMT Organization: Dartmouth College, Hanover, NH argc and argv do not work at all on any normal mac setup. Sorry. The following program fragment gives an idea of how to get the old-fashioned app params (files to open or print). If you want to do anything more complicated, you'll need to use Apple Events. /* openingFiles( ) ** ** Determine if we have parameters. The old-style app parameters are used for ** the sake of SPEED. Apple Events are too slow, and I only have partial docs. ** Help in acquiring copies of Inside Macintosh always welcome... */ Boolean openingFiles( ) { short message; short count; CountAppFiles( &message, &count ); return ( message == 0 && count > 0 ); } /* openFiles( ) ** ** Go through files one by one, processing them along the way. */ void openFiles( ) { FSSpec cur; AppFile aFile; short count; short i; short mess; /* I'm not bothering to check for print messages--my app shouldn't get any */ CountAppFiles( &mess, &count ); for ( i = 1; i <= count; i++ ) { /* get file and convert from working dir to FSSpec */ GetAppFiles( i, &aFile ); FSMakeFSSpec( aFile.vRefNum, 0, aFile.fName, &cur ); processFile( &cur ); } } main( ) { initMacintosh( ); initApplication( ); if ( openingFiles( ) ) openFiles( ); else runApplication( ); } +++++++++++++++++++++++++++ >From ruhl@du.edu (ROBERT A. UHL ) Date: Fri, 23 Sep 1994 15:34:11 GMT Organization: University of Denver Does anybody have the format of the Handle returned by GetAppParms()? I don't have IM and have to figure out what the functions do from the headers. Any help would be appreciated. -- - ------------------------------------ | Bob Uhl | Spectre | | U of D | Baron Robert von Raetzin | +++++++++++++++++++++++++++ >From Carl R. Osterwald Date: Fri, 23 Sep 1994 20:48:32 GMT Organization: National Renewable Energy Laboratory In article <35ssck$m3a@geraldo.cc.utexas.edu> victor chong, victorc@sleepy.cc.utexas.edu writes: > I was wondering if someone could enlighten me concerning >the usage of argv and argc when programming on the Macintosh. >I'm using Symantec C++. > Does the Mac allows this kind of communication with the >OS or is there another method. Just use the Symantec console package. You will need to add one key element, a ccommand() call, before you access argv/argc. This puts up a dialog box that allows you to type in the command line parameters. ccommand() was documented in the Think C 5 manuals, in 6 and 7 it is online inside the free version of Think Reference (I have not verified this personally). For disk I/O be sure to check the c.s.m.p PD programming FAQ compiled by Jon Watte. +++++++++++++++++++++++++++ >From rrk@rahul.net (Bob R. Kenyon) Date: Sat, 24 Sep 1994 05:54:04 GMT Organization: La Casita de Las Pulgas, San Jose, CA In article <35ssck$m3a@geraldo.cc.utexas.edu>, victor chong wrote: > Hi, > I was wondering if someone could enlighten me concerning > the usage of argv and argc when programming on the Macintosh. > I'm using Symantec C++. > Does the Mac allows this kind of communication with the > OS or is there another method. > Any kind of help will be much welcome. > Thank you very much. Yeah, if you look in Think Reference, they talk about a function called ccommand. When your program starts, it throws up a window that allows you to redirect input and output, and enter command line arguments. It's pretty funny actually, but not really "Mac" in behavior. Their code example looks like this: /* CODE EXAMPLE #1 */ #include #include main(int argc, char **argv) { int i; argc = ccommand(&argv); // this is the command that throws up the window for (i=0; iFrom ferrari@netaxs.com (Darrell Turner) Subject: How to Check if drivers are open Date: Thu, 22 Sep 1994 13:26:38 -0500 Organization: Haha, None here I'm trying to figure out how to check if a driver is open by only specifying the driver name. I want it to work for .IPP .AOut, and others such as ram serail drivers for Hurdlers, etc. My problem is that I can't figure out if it's open without first knowing the driver unit number. I was going to walk the UnitTable checking for the Driver Name in the DCtlEntry, but I soon discovered that the name is in there. This is my current code, and it doesn't work, how can I get this working? (The GetNamedResource returns nil, even on stuff I know is in the System file like .AOut. function GetNamedDCtlEntry (driverName: str255): DCtlHandle; type Ptr2Word = ^integer; Ptr2Byte = ^byte; const UnitNtryCnt = $1D2; {[GLOBAL VAR] count of entries in unit table [word]} RomMapInsert = $B9E;{[GLOBAL VAR] (byte) determines if we should link in map} var rID: integer; rType: ResType; hand: handle; begin SetResLoad(false); Ptr2Byte(RomMapInsert)^ := 1; hand := GetNamedResource('DRVR', driverName); SetResLoad(true); GetResInfo(hand, rID, rType, driverName); if (rID >= 0) and (rID <= Ptr2Word(UnitNtryCnt)^) then GetNamedDCtlEntry := GetDCtlEntry(rID) else GetNamedDCtlEntry := nil; end; begin dctl := GetNamedDCtlEntry('.IPP'); if dCtl = nil then Quit(noErr); Init; repeat HandleEvents; until (BitTst(@dctl^^.dCtlFlags, 5) or done); {...} end. +++++++++++++++++++++++++++ >From resnick@uiuc.edu (Pete Resnick) Date: Fri, 23 Sep 1994 12:36:16 -0500 Organization: University of Illinois at Urbana-Champaign In article , ferrari@netaxs.com (Darrell Turner) wrote: > I'm trying to figure out how to check if a driver is open by only > specifying the driver name. I want it to work for .IPP .AOut, and others > such as ram serail drivers for Hurdlers, etc. > > My problem is that I can't figure out if it's open without first knowing > the driver unit number. I was going to walk the UnitTable checking for the > Driver Name in the DCtlEntry, but I soon discovered that the name is in > there. Yes it is. It's in the driver itself, which is pointed to by the DCtl entry. Here's some code (in C; the conversion to Pascal is pretty easy): /* Structure of the driver resource */ typedef struct { short drvrFlags; short drvrDelay; short drvrEMask; short drvrMenu; short drvrOpen; short drvrPrime; short drvrCtl; short drvrStatus; short drvrClose; unsigned char drvrName[]; unsigned char drvrRoutines[]; } DriverStruct, *DriverPtr, **DriverHandle; #if define(__SYSEQU__) #define UTABLEBASE (* (DCtlHandle **)UTableBase) #define UNITNTRYCNT (* (short *)UnitNtryCnt) #elif defined(__LOWMEM__) #define UTABLEBASE (DCtlHandle *)LMGetUTableBase() #define UNITNTRYCNT LMGetUnitNtryCnt() #else #define UTABLEBASE UTableBase #define UNITNTRYCNT UnitNtryCnt #endif #ifndef dOpened # define dOpened 0x0020 #endif /* dOpened */ #ifndef dRAMBased # define dRAMBased 0x0040 #endif /* dRAMBased */ short GetDrvrRefNum(StringPtr drvrName) { short unitNum; DCtlPtr curDCtlPtr, *curDCtlHndl, **UTableEntry; DriverPtr curDrvrPtr; /* Walk through the Unit Table */ UTableEntry = UTABLEBASE; for(unitNum = 0; unitNum < UNITNTRYCNT; ++unitNum) { if((curDCtlHndl = *UTableEntry++) != nil) { curDCtlPtr = *curDCtlHndl; /* Get the pointer to the driver */ curDrvrPtr = (DriverPtr)curDCtlPtr->dCtlDriver; /* If this is a RAM driver, it's a handle. ROM is a pointer */ if((curDCtlPtr->dCtlFlags & dRAMBased) && (curDrvrPtr != nil)) curDrvrPtr = *(DriverPtr *)curDrvrPtr; /* Does the driver name match? */ if(curDrvrPtr != nil) if(EqualString(drvrName, curDrvrPtr->drvrName, false, true)) return(~unitNum); } } return(0); } Boolean IsDriverOpen(StringPtr drvrName) { short unitNum; DCtlPtr curDCtlPtr, *curDCtlHndl, **UTableEntry; DriverPtr curDrvrPtr; /* Walk through the Unit Table */ UTableEntry = UTABLEBASE; for(unitNum = 0; unitNum < UNITNTRYCNT; ++unitNum) { if((curDCtlHndl = *UTableEntry++) != nil) { curDCtlPtr = *curDCtlHndl; /* Get the pointer to the driver */ curDrvrPtr = (DriverPtr)curDCtlPtr->dCtlDriver; /* If this is a RAM driver, it's a handle. ROM is a pointer */ if((curDCtlPtr->dCtlFlags & dRAMBased) && (curDrvrPtr != nil)) curDrvrPtr = *(DriverPtr *)curDrvrPtr; /* Does the driver name match? */ if(curDrvrPtr != nil) if(EqualString(drvrName, curDrvrPtr->drvrName, false, true)) return((curDCtlPtr->dCtlFlags & dOpened) != 0); } } return(false); } Note: There is an omission in the Universal headers LowMem.h because it does not define LMGetUnitNtryCnt or LMSetUnitNtryCnt. For the 68000 versions, add: #define LMGetUnitNtryCnt() (* (short *) 0x01D2) #define LMSetUnitNtryCnt(UnitNtryCntValue) ((* (short *) 0x01D2) = (UnitNtryCntValue)) I don't know what to do about the PowerPC versions. pr -- Pete Resnick (...so what is a mojo, and why would one be rising?) Doctoral Student - Philosophy Department, Gregory Hall, UIUC System manager - Cognitive Science Group, Beckman Institute, UIUC Internet: resnick@uiuc.edu +++++++++++++++++++++++++++ >From csuley@netcom.com (Christopher S. Suley) Date: Sat, 24 Sep 1994 05:58:12 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) Here's some code I use to find a driver in the unit table. It's lightly adapted from Pete Resnick's excellent Driver 2.2, available at sumex and umich and mirrors thereof. It's in C, but the translation to Pascal should be pretty easy. typedef struct { short drvrFlags; short drvrDelay; short drvrEMask; short drvrMenu; short drvrOpen; short drvrPrime; short drvrCtl; short drvrStatus; short drvrClose; unsigned char drvrName[1]; /* actually variable length p-string */ } DriverStruct, *DriverPtr; short FindDriver( void ) { Str255 drvrName; DCtlHandle hCurDCE; DriverPtr pCurDrvr; short sDrvrNum; GetIndString( drvrName, krMiscStrings, ksiDriverNameIndex ); for ( sDrvrNum = LMGetUnitNtryCnt() ; sDrvrNum >= 0 ; --sDrvrNum ) { hCurDCE = GetDCtlEntry( ~sDrvrNum ); if ( hCurDCE ) { pCurDrvr = ( DriverPtr ) (**hCurDCE).dCtlDriver; if ( ((**hCurDCE).dCtlFlags & dRAMBased) && pCurDrvr ) { pCurDrvr = *( DriverPtr * ) pCurDrvr; } if ( pCurDrvr && EqualString( drvrName, pCurDrvr->drvrName, false, true ) ) { return ~sDrvrNum; } } } return 0; } -- Want some? csuley@netcom.com Want some? ChrisSuley@{eworld,aol}.com --------------------------- >From altitude@umich.edu (Alex Tang) Subject: Is it possible to notify another mac? Date: 23 Sep 1994 21:09:51 GMT Organization: University of Michigan Hi folks. I was wondering if it was possible to pull up a dialog box or alert box on another mac via either AppleTalk or IP. Me 'n some friends want to write an app that will (in it's most simple incarnation) open up an alert box on another mac and give them a piece of information. In it's most complicated incarnation, we would really like to be able to have one mac contact the notification manager on another mac, and run a program on that mac. This is all presuming we know the AppleTalk node or IP address of the sending and receiving mac. Thanx ...alex... -- Alex Tang | UM-SNRE | UM-ITD/US Consultant II ALTITUDE@UMICH.EDU | Student | UM-SNRE-NCEET: Systems Admin PGP via finger. | Systems Admin |http://www.snre.umich.edu/users/altitude This space for rent|Comp.Consut III| An eye for an eye leaves everyone blind. +++++++++++++++++++++++++++ >From nick+@pitt.edu ( nick.c ) Date: Fri, 23 Sep 94 20:42:20 GMT Organization: The Pitt, Chemistry In Article <35vg70$7v6@lastactionhero.rs.itd.umich.edu>, altitude@umich.edu (Alex Tang) wrote: >I was wondering if it was possible to pull up a dialog box or alert box on >another mac via either AppleTalk or IP. > >Me 'n some friends want to write an app that will (in it's most simple >incarnation) open up an alert box on another mac and give them a piece of >information. > >In it's most complicated incarnation, we would really like to be able to >have one mac contact the notification manager on another mac, and run a >program on that mac. Possible and been done. I remember seeing a notification like program on Umich... forget the name... "Broadcast"?. Dunno. Anyway, as I recall you have to have program linking on on the receiving mac, and have to have loaded an extension on the receiving mac that takes your message and forwards it to the local notification manager. You could also create an extension that sends out apple events, so could launch a local program when keyed remotely. I'd check out NIM:networking for more details, luck -- nick _/ _/ _/ _/_/_/ _/ _/ Interet: nick@pitt.edu _/_/ _/ _/ _/ _/ _/_/_/ eWorld: nick _/ _/_/ _/ _/ _/ _/ CIS: 71232,766 _/ _/ _/ _/_/_/ _/ _/ +++++++++++++++++++++++++++ >From jonasw@lysator.liu.se (Jonas Wallden) Date: 24 Sep 1994 21:19:28 GMT Organization: (none) altitude@umich.edu (Alex Tang) writes: >Hi folks. > >I was wondering if it was possible to pull up a dialog box or alert box on >another mac via either AppleTalk or IP. > >Me 'n some friends want to write an app that will (in it's most simple >incarnation) open up an alert box on another mac and give them a piece of >information. > >In it's most complicated incarnation, we would really like to be able to >have one mac contact the notification manager on another mac, and run a >program on that mac. > >This is all presuming we know the AppleTalk node or IP address of the >sending and receiving mac. A nice little hack is 'Radiation + Trigger' which can be used to fake error messages on anoter Mac's screen. Very useful in lab rooms... :-) It is an INIT that receives messages through the PPC Toolbox and displays them as Notification Manager alerts. BTW, the default message is 'The radiation shield on your Macintosh has failed. Please step back 5 feet.' which explains its name... Use with care on newbies! -- `.`. Jonas Wallden `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`. Internet: jonasw@lysator.liu.se `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`.`. AppleLink: sw1369 `.`.`.`.`.`.`.`.`.`.`.`.`.`.`. --------------------------- >From jlawrie@malibu.sfu.ca (John William Lawrie) Subject: Memory moving and Inits Date: 16 Sep 94 17:13:25 GMT Organization: Simon Fraser University Hi. I want to have an extension that performs periodic taks. I have a skeleton extension that does this already, but the problem is, I will want to call toolbox routines that will call the memory manager. Is there a way around this? John@helix.net +++++++++++++++++++++++++++ >From onyxtech@aol.com (OnyxTech) Date: 17 Sep 1994 04:26:02 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , jlawrie@malibu.sfu.ca (John William Lawrie) writes: > Hi. I want to have an extension that performs periodic > taks. I have a skeleton extension that does this already, > but the problem is, I will want to call toolbox routines > that will call the memory manager. Is there a way around > this? It's ok to move memory in a trap patch, but It all depends on what you're using to trigger your extension code? If you're installing a time manager or VBL routine, forget trying to move memory during that code because they can/will be executed during interupt time and moving memory then is a strict no no. If you are triggering your extension code off a trap patch, them make sure it is a trap patch that can move memory. Then you're ok. If you are triggering off a trap patch that isn't documented as moving memory, you'd better change your code because you'll eventually get in trouble. And since I'm not sure what you're patching, better make sure that what your trap patch calls does not lead to what you're patching. Re-entrant city unless you handle it correctly. dEVoN +++++++++++++++++++++++++++ >From jcornish@netcom.com (Jud Cornish) Date: Sun, 18 Sep 1994 08:32:34 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) To perform periodic tasks that may move/purge memory: A simple solution is to patch a trap (or several) that are known to move/purge memory and are commonly called. I did some "OS Profiling" of my own to identify a set of traps that I could patch that would give frequent time to such a task. The other objective was to get time when apps, the OS or the Toolbox is in a tight loop such as while tracking a close box. If you patch any one trap, there will be times when you can go for quite some time without an opportunity to snag some time. I shouldn't go into the details, but with some common sense (and a little time with macsbug) one can pick a pretty good set of traps. All this is only necessary if you have a really critical time based task. Not critical in accuracy, but in avoiding long pauses. All this is necessary because of the way "multi-tasking" is done on the mac. Processes are only granted time when others share it. Another option would be to install a driver which requested periodic time. This is actually harder than just patching _SystemTask, which I believe would function identically. Yet another option is to pre-allocate some memory with your INIT, then eat it up as you need it. In a sense, depending on the complexity of your memory use, you can just start filling up a simple buffer with data, or you could make your own sub memory manager!!! A hybrid solution is to perform periodic tasks via the time manager, with accuracy and nearly guaranteed time, then when you fill up your buffer (or get sufficiently close to it), you set a flag which a _SystemTask patch can use to know when to grow the buffer. You would need to temporarily suspend your use of the buffer while the patch is growing (and probably moving) it. This can be done with another flag manipulated just before and after the SetHandleSize. The periodic task would always make sure this flag was clear before dereferencing the handle and using the buffer. I have little idea what your actual needs are but I hope that this discussion is helpful. Hopefully, a simple patch will suffice. As far as I have seen (68k sys 7.5), the OS still calls _SystemTask periodically. If this is indeed the case, it is a good target as other processes will expect to share time when this happens (usually from a _waitNextEvent call). Any comments on my comments would be appreciated. Erik J. Rogers +++++++++++++++++++++++++++ >From resnick@uiuc.edu (Pete Resnick) Date: Sun, 18 Sep 1994 13:00:37 -0500 Organization: University of Illinois at Urbana-Champaign In article , jlawrie@malibu.sfu.ca (John William Lawrie) wrote: > Hi. I want to have an extension that performs periodic taks. I have > a skeleton extension that does this already, but the problem is, I > will want to call toolbox routines that will call the memory manager. > Is there a way around this? My personal favorite is to use a Time Manager task to do the periodic part, and have the completion proc for the Time Manager routine post a Notification Manager request that has all the fields except nmResp cleared. In the notification response, you can do whatever you want to do since it is Memory Manager safe. pr -- Pete Resnick (...so what is a mojo, and why would one be rising?) Doctoral Student - Philosophy Department, Gregory Hall, UIUC System manager - Cognitive Science Group, Beckman Institute, UIUC Internet: resnick@uiuc.edu +++++++++++++++++++++++++++ >From Jaeger@fquest.com (Brian Stern) Date: 19 Sep 1994 05:03:25 GMT Organization: The University of Texas at Austin, Austin, Texas In article , jlawrie@malibu.sfu.ca (John William Lawrie) wrote: < Hi. I want to have an extension that performs periodic taks. I have < a skeleton extension that does this already, but the problem is, I < will want to call toolbox routines that will call the memory manager. < Is there a way around this? < < John@helix.net A jGNEFilter is a simple way to get periodic time and you can move memory if you need to. The only problem is that you aren't guaranteed that it will be called frequently. -- Brian Stern :-{)} Jaeger@fquest.com +++++++++++++++++++++++++++ >From blob@apple.com (Brian Bechtel) Date: 24 Sep 1994 14:39:56 -0700 Organization: Apple Computer, Inc., Cupertino, California Jaeger@fquest.com (Brian Stern) writes: >In article , jlawrie@malibu.sfu.ca (John William >Lawrie) wrote: >< Hi. I want to have an extension that performs periodic taks. I have >< a skeleton extension that does this already, but the problem is, I >< will want to call toolbox routines that will call the memory manager. >< Is there a way around this? >A jGNEFilter is a simple way to get periodic time and you can move memory >if you need to. The only problem is that you aren't guaranteed that it >will be called frequently. Even better is a faceless background application. You can call any toolbox routine that doesn't provide a user interface. You get time like any other application. --Brian Bechtel blob@apple.com "My opinion, not Apple's" --------------------------- >From ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) Subject: Self-disposing notification crashes Date: 16 Sep 94 16:35:09 +1200 Organization: University of Waikato, Hamilton, New Zealand I'm working on this MPW tool that sends a PostScript stream to a printer via PAP, and displays whatever the printer sends back. It loads the PDEF 10 code from the LaserWriter driver (I know, I know, but this is for in-house use, and I have ways of keeping it working under QuickDraw GX ;-)). However, I didn't like the PAPStatus call that that library provides, as it's synchronous, and tends to hang for several seconds if the printer goes away. So I tried implementing my own version of PAPStatus. My version allocates a temporary block in the heap, which is used to contain the context for the call, including pointers to the user's data areas. Once the query starts, everything runs at interrupt time as a sequence of chained completion routines from then on, except of course for the last bit of code that gets rid of the temporary block. This code runs as a notification routine, so that it's safe for it to make Memory Manager calls. The notification code is actually copied into the temporary block, and executes out of there. I did this as part of a strategy for dealing cleanly with aborting execution of the tool, though admittedly my handling of this is not complete as yet. Anyway, this notification routine is very small, and is written in assembler. Here it is in its entirety: move.l 4(sp), a0 _NMRemove move.l NMRec.nmRefCon(a0), a0 _DisposePtr move.l (sp)+, (sp) rts Note that the DisposePtr call is disposing of the block containing the code (and the notification record) itself! However, I have stepped through this code with MacsBug, and watched it successfully return from DisposePtr and execute those last two instructions just fine. Basically, the problem is, my tool tends to crash, but only the second time it runs. The first time is always fine: I can send a large multi-page print job to the printer (with lots of status queries throughout), or I can send a small one-line query, and it will always work. However, the second time I try invoking my tool, it will crash. I finally narrowed it down to one thing: the DisposePtr call in the notification routine, above. If I no-op out the dispose call (causing a resultant accumulation of allocated memory blocks in MPW's heap), I can run the tool multiple times just fine. Anybody got any ideas as to why this can't work? Thanks for any help. Lawrence D'Oliveiro fone: +64-7-856-2889 Info & Tech Services Division fax: +64-7-838-4066 University of Waikato electric mail: ldo@waikato.ac.nz Hamilton, New Zealand 37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00 +++++++++++++++++++++++++++ >From pottier@fregate.ens.fr (Francois Pottier) Date: 16 Sep 1994 11:28:28 GMT Organization: Ecole Normale Superieure, PARIS, France In article <1994Sep16.163509.33240@waikato.ac.nz>, Lawrence D'Oliveiro, Waikato University wrote: > >Anyway, this notification routine is very small, and is written in assembler. >Here it is in its entirety: > > move.l 4(sp), a0 > _NMRemove > move.l NMRec.nmRefCon(a0), a0 > _DisposePtr > move.l (sp)+, (sp) > rts > >Note that the DisposePtr call is disposing of the block containing the code I'm interested in this problem too. My notification routine looks exactly the same way. It works perfectly, but I'm concerned that it might break in the future. Apple has warned against this sort of thing; once the block is freed, you can't make any assumptions about its contents (so you can't execute code in it). This makes sense; in a preemptive multitasking system, the block could very well by allocated by another process before you have time to rts out of it. However, I don't see any other way of disposing properly of the Notification Record. If you want your notification to appear after your normal code is dead (INITs need to do that), then you must copy the response proc into a standalone block in the System heap. And if you want to clean up properly, you should release this block after it's been used. So there appears to be no way to do the Right Thing here. I'd be interested in comments... -- Francois Pottier pottier@dmi.ens.fr - ---------------------------------------------------------------------------- Check my WWW page at http://acacia.ens.fr:8080/home/pottier/index.html ... +++++++++++++++++++++++++++ >From Jaeger@fquest.com (Brian Stern) Date: 16 Sep 1994 15:48:28 GMT Organization: The University of Texas at Austin, Austin, Texas In article <35bvgs$h87@nef.ens.fr>, pottier@fregate.ens.fr (Francois Pottier) wrote: < However, I don't see any other way of disposing properly of the Notification < Record. If you want your notification to appear after your normal code is < dead (INITs need to do that), then you must copy the response proc into a < standalone block in the System heap. And if you want to clean up properly, < you should release this block after it's been used. So there appears to be < no way to do the Right Thing here. < < I'd be interested in comments... < < < < < -- < Francois Pottier pottier@dmi.ens.fr < ------------------------------------------------------------------------------ < Check my WWW page at http://acacia.ens.fr:8080/home/pottier/index.html ... If you check out Dair Grant's Init Shell package, at an ftp site near you, you'll find some code that gets around this problem. It works by poking several instructions into ToolScratch, including the disposePtr, and then jumping to those instructions. I believe this is based on some code that was in the old usenet mac programmers guide. Cheers, -- Brian Stern :-{)} Jaeger@fquest.com +++++++++++++++++++++++++++ >From resnick@uiuc.edu (Pete Resnick) Date: Fri, 16 Sep 1994 15:00:26 -0500 Organization: University of Illinois at Urbana-Champaign In article <1994Sep16.163509.33240@waikato.ac.nz>, ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) wrote: > Anyway, this notification routine is very small, and is written in assembler. > Here it is in its entirety: > > move.l 4(sp), a0 > _NMRemove > move.l NMRec.nmRefCon(a0), a0 > _DisposePtr > move.l (sp)+, (sp) > rts > > Note that the DisposePtr call is disposing of the block containing the code > (and the notification record) itself! However, I have stepped through this > code with MacsBug, and watched it successfully return from DisposePtr and > execute those last two instructions just fine. Yow!! This would be bad since you can't depend on when that memory is going to be overwritten, and for you, it's happening in the call to _DisposePtr. There are two ways around this: On anything better than a 68010 (which is all Macs except for the classic one) there is a wonderful little instruction: RTD. That instruction returns, but also simultaneously deallocates space on the stack. So, what I do is call _NMRemove (and whatever other cleanup I want to do) and then move the _DisposePtr and an RTD instruction to the stack: move.l 4(sp),a0 ; Move the NMRec _NMRemove ; Remove it move.l NMRec.nmRefCon(a0),a1 ; Address of code+NMRec into A1 movea.l (sp)+,a0 ; Return address into A0 move.l #$4E740006,-(sp) ; RTD #$0006 move.w #$a01f,-(sp) ; _DisposePtr move.l a0,-(sp) ; Return address back onto stack pea 4(sp) ; Address of _DisposePtr on stack moveq #$1,d0 _HWPriv ; Flush the cache movea.l a1,a0 ; Address to dispose rts ; Return to _DisposePtr on stack So the stack (before the final RTS) looks like: +0000 +0004 +0008 _DisposePtr +000A RTD #$0006 .....Rest of stack So when that last RTS executes, it rips the address of sp+8 off of the stack and jumps to it. The _DisposePtr disposes what's in A0 (the code and the NMRec), then the RTD takes the old return address off the stack, moves the stack pointer 6 bytes (past the _DisposePtr and the RTD #$0006), and jumps to the return address. Frightening, eh? On the old 68000, you don't have the RTD instruction (nor an instruction cache), but life is generally a good deal simpler: There is a low memory global called "ToolScratch", which is an 8-byte scratch area. It stays constant across the call to _DisposePtr, so what you can do instead is: move.l 4(sp),a1 ; Move the NMRec move.l (sp)+,(sp) ; Move the return address into place _NMRemove ; Remove it move.l NMRec.nmRefCon(a1),a0 ; Address of code+NMRec into A0 movea.w #ToolScratch,a1 ; Address of the LM global move.l a1,-(sp) ; Put the address onto the stack move.l #$a01f4E75,(a1) ; _DisposePtr / RTS rts So now the stack looks like: +0000
+0004 .....Rest of stack And ToolScratch has in it: _DisposePtr RTS This has worked perfectly for me. Executing code on the stack is pretty wierd, but it works just great. pr -- Pete Resnick (...so what is a mojo, and why would one be rising?) Doctoral Student - Philosophy Department, Gregory Hall, UIUC System manager - Cognitive Science Group, Beckman Institute, UIUC Internet: resnick@uiuc.edu +++++++++++++++++++++++++++ >From jberry@teleport.com (James D. Berry) Date: Fri, 16 Sep 1994 13:39:16 -0700 Organization: Consultant In article <1994Sep16.163509.33240@waikato.ac.nz>, ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) wrote: > Anyway, this notification routine is very small, and is written in assembler. > Here it is in its entirety: > > move.l 4(sp), a0 > _NMRemove > move.l NMRec.nmRefCon(a0), a0 > _DisposePtr > move.l (sp)+, (sp) > rts > > Note that the DisposePtr call is disposing of the block containing the code > (and the notification record) itself! However, I have stepped through this > code with MacsBug, and watched it successfully return from DisposePtr and > execute those last two instructions just fine. I can't see the rest of your code, but it strikes me that if for some reason the NMRemove call is being passed an incorrect value, then you'd be leaving a bogus link in the NMQueue (because you've deleted the code it's pointing to) which would cause a crash on the next invokation. I'm a purest at heart, and also don't like the fact that you're executing two instructions out of a block that's been disposed. The Modern Memory Manager, in fact, has a debug mode that'll trash blocks as they're disposed, which should break your code. I use the following code to (cleanly?) cleanup following a notification. Note that it assumes the NMRec and supporting code are all allocated into a single heap block. It hasn't yet (!!) managed to break the 68K emulator, though it seems a good target to :-() Now if Apple would just give us a few NM flags that specify a block to be deleted following notification! ;------------------------------------------------------------ ; pascal void NotifyProc(NMRecPtr pRec) ; ; The notify proc. Its sole purpose in life is to ; clean-up following the notification manager. ;------------------------------------------------------------ NotifyProc proc machine mc68020 entry NotifyProcLen subq #2,sp ; Extra space 8 bytes --> 10 bytes move.l 2(sp),-(sp) ; Move Return address move.l 10(sp),-(sp) ; Move NMRecPtr lea @StackCodeEnd,a1 ; Move our _DisposePtr code onto stack lea 14(sp),a0 ; so that we can suicide cleanly! move.l -(a1),-(a0) ; rtd #x move.w -(a1),-(a0) ; _DisposePtr moveq #6,d0 ; Length of the code move.l d0,a1 ; into a1 _FlushCodeCacheRange ; Flush the caches where we wrote code move.l a0,a1 ; Pointer to our cleanup code on stack move.l (sp)+,a0 ; Get NMRecPtr _NMRemove ; Unqueue the NMRec jmp (a1) ; Call cleanup code to dispose the block we're ; currently executing out of ; This code will be moved onto the stack ; before it is executed, so that we don't ; execute code out of a deallocated block _DisposePtr ; Dispose the NMRec/code/string block rtd #6 ; Return to caller, deallocating this code! @StackCodeEnd NotifyProcLen dc.l *-NotifyProc ; Length of our notification proc endp -- James Berry jberry@teleport.com +++++++++++++++++++++++++++ >From Bruce@hoult.actrix.gen.nz (Bruce Hoult) Date: Sat, 17 Sep 1994 14:50:34 +1200 (NZST) Organization: (none) ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) writes: > I'm working on this MPW tool that sends a PostScript stream to a printer via > PAP, and displays whatever the printer sends back. Heh. I turned your downloader XCMDs into an MPW Tool only about -- what? -- seven years ago. > It loads the PDEF 10 code > from the LaserWriter driver (I know, I know, but this is for in-house use > and I have ways of keeping it working under QuickDraw GX ;-)). Hmm. Looks as if I'm going to need an update :-( > I finally narrowed it down to one thing: the DisposePtr call in the > notification routine, above. If I no-op out the dispose call (causing a > resultant accumulation of allocated memory blocks in MPW's heap), I can run the > tool multiple times just fine. > > Anybody got any ideas as to why this can't work? It's not going to like the Modern Memory Manager, which stores some info inside your data block as soon as you dispose it. OTOH, if the last two instructions are surviving then it's hard to see what's going wrong. You *are* allocating a new block and a new copy of the code each time you use it, right? Might you not be better to allocate a small block the first time you run and just leave it alive? And use Gestalt or something to find it each time? -- Bruce +++++++++++++++++++++++++++ >From ludis@netcom.com (Ludis Langens) Date: Sat, 17 Sep 1994 23:28:18 GMT Organization: Netcom Online Communications Services (408-241-9760 login: guest) In article <35bvgs$h87@nef.ens.fr> pottier@fregate.ens.fr (Francois Pottier) writes: >In article <1994Sep16.163509.33240@waikato.ac.nz>, >Lawrence D'Oliveiro, Waikato University wrote: >> >>Anyway, this notification routine is very small, and is written in assembler. >>Here it is in its entirety: >> >> move.l 4(sp), a0 >> _NMRemove >> move.l NMRec.nmRefCon(a0), a0 >> _DisposePtr >> move.l (sp)+, (sp) >> rts >> >>Note that the DisposePtr call is disposing of the block containing the code > >I'm interested in this problem too. My notification routine looks exactly >the same way. It works perfectly, but I'm concerned that it might break in >the future. > >Apple has warned against this sort of thing; once the block is freed, you >can't make any assumptions about its contents (so you can't execute code in >it). This makes sense; in a preemptive multitasking system, the block could >very well by allocated by another process before you have time to rts out of >it. > >However, I don't see any other way of disposing properly of the Notification >Record. If you want your notification to appear after your normal code is >dead (INITs need to do that), then you must copy the response proc into a >standalone block in the System heap. And if you want to clean up properly, >you should release this block after it's been used. So there appears to be >no way to do the Right Thing here. To dispose the memory block out of which you are executing, try this: BlockStart EQU * ... MOVEQ #$1F,D0 ;Trap number of DisposPtr _GetTrapAddress OS MOVE.L A0,A1 LEA BlockStart(PC),A0 JMP (A1) Use this code as the very last thing you execute. Make sure you have removed any parameters from the stack (so that an RTS can return to your caller.) The JMP (A1) goes to the memory manager directly, bypassing the trap dispatcher. This means that registers D0-D2/A0-A1 may be changed. Once DisposPtr has freed the block, it will return (directly) to your caller. When you link your code fragment, make sure that BlockStart is at offset 0 in the memory block. This same trick can be also be used with handles by adding a RecoverHandle (and getting the address of DisposHandle.) Ludis Langens ludis@netcom.com +++++++++++++++++++++++++++ >From ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) Date: 19 Sep 94 14:24:01 +1200 Organization: University of Waikato, Hamilton, New Zealand In article , jberry@teleport.com (James D. Berry) writes: > In article <1994Sep16.163509.33240@waikato.ac.nz>, ldo@waikato.ac.nz > (Lawrence D'Oliveiro, Waikato University) wrote: > >> Anyway, this notification routine is very small, and is written in assembler. >> Here it is in its entirety: >> >> move.l 4(sp), a0 >> _NMRemove >> move.l NMRec.nmRefCon(a0), a0 >> _DisposePtr >> move.l (sp)+, (sp) >> rts >> >> Note that the DisposePtr call is disposing of the block containing the code >> (and the notification record) itself! However, I have stepped through this >> code with MacsBug, and watched it successfully return from DisposePtr and >> execute those last two instructions just fine. > > I can't see the rest of your code, but it strikes me that if for some > reason the NMRemove call is being passed an incorrect value, then you'd be > leaving a bogus link in the NMQueue (because you've deleted the code it's > pointing to) which would cause a crash on the next invokation. The NMRec address must be correct, because its nmRefCon contains the pointer to the entire block, which is indeed being correctly disposed. (Like I said, I checked this with MacsBug.) > I'm a purest at heart, and also don't like the fact that you're executing > two instructions out of a block that's been disposed. The Modern Memory > Manager, in fact, has a debug mode that'll trash blocks as they're > disposed, which should break your code. That must be the only memory manager in the world that does that... Lawrence D'Oliveiro fone: +64-7-856-2889 Info & Tech Services Division fax: +64-7-838-4066 University of Waikato electric mail: ldo@waikato.ac.nz Hamilton, New Zealand 37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00 "Icons are the droppings located at the top and sides of the Windows display." -- reported in PC Magazine +++++++++++++++++++++++++++ >From jan3@po.cwru.edu (James A. Nauer) Date: Mon, 19 Sep 1994 17:18:49 -0400 Organization: Case Western Reserve University In article <1994Sep19.142402.33297@waikato.ac.nz>, ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) wrote: > In article , jberry@teleport.com (James D. Berry) writes: > > > > I'm a purest at heart, and also don't like the fact that you're executing > > two instructions out of a block that's been disposed. The Modern Memory > > Manager, in fact, has a debug mode that'll trash blocks as they're > > disposed, which should break your code. > > That must be the only memory manager in the world that does that... Not true. I have an anti-virus TSR on my PC which, among other things, patches the (feeble) DOS memory management routines to zero out all freed blocks before returning. Naturally, I also have a couple of programs that fail because they think they can get away with using a few bytes of data in a block _after_ freeing it :-(. -- James A. Nauer | "I shall not yield one whit of maturity, Library Information | not grace, not respectibility, to the Technologies | passing of time. I declare that I shall Case Western Reserve Univ. | forever be, if not a child, certainly (216) 368-MACS (368-6227) | childish" --Kennet Shardik +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Tue, 20 Sep 1994 10:36:19 +0200 Organization: Royal Institute of Something or other In article <1994Sep19.142402.33297@waikato.ac.nz>, ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) wrote: >> two instructions out of a block that's been disposed. The Modern Memory >> Manager, in fact, has a debug mode that'll trash blocks as they're >> disposed, which should break your code. > >That must be the only memory manager in the world that does that... Not at all; several malloc() implementations IMMEDIATELY writes data into the block being disposed, like a pointer in a linked list of free blocks, or something like that. Using a block after disposing it is BAD BAD BAD. The Cleanup/GetTrapAddress/Jump solution is the only clean one, but depends on the fact that DisposePtr uses register calling conventions. Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden V}ga v{gra nonkonformism! +++++++++++++++++++++++++++ >From fixer@faxcsl.dcrt.nih.gov (Chris Biscottimeister Tate) Date: Tue, 20 Sep 1994 18:44:17 GMT Organization: DCRT, NIH, Bethesda, MD In article <1994Sep19.142402.33297@waikato.ac.nz>, ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) writes: >In article , jberry@teleport.com (James D. Berry) writes: >> >> I'm a purist at heart, and also don't like the fact that you're executing >> two instructions out of a block that's been disposed. The Modern Memory >> Manager, in fact, has a debug mode that'll trash blocks as they're >> disposed, which should break your code. > >That must be the only memory manager in the world that does that... I seem to recall running into some odd situations in which the system was writing into unallocated heap memory for some reason. Quickdraw, maybe? (I would think that executing out of a just-deallocated block is pretty much a recipe for disaster - certainly in a preemptive-multitasking world you're doomed if you do it, barring some IMHO unwarranted privileges being granted to your code...) - ------------------------------------------------------------------ Christopher Tate | "Apple Guide makes Windows' help engine MSD, Inc. | look like a quadruple amputee." fixer@faxcsl.dcrt.nih.gov | -- Pete Gontier (gurgle@dnai.com) +++++++++++++++++++++++++++ >From rang@winternet.com (Anton Rang) Date: 21 Sep 1994 01:06:37 GMT Organization: Trillium Research, Inc. In article <9668AAA46BA3.6ED60@klkmac018.nada.kth.se> h+@nada.kth.se (Jon W{tte) writes: >Using a block after disposing it is BAD BAD BAD. The >Cleanup/GetTrapAddress/Jump solution is the only clean one, but >depends on the fact that DisposePtr uses register calling >conventions. Actually, you're fine with Pascal calling conventions, too, since the callee is responsible for cleaning up the stack. It's only if you are trying to use C calling conventions that you'll have problems with exiting via a call to another routine. -- Anton Rang (rang@winternet.com) +++++++++++++++++++++++++++ >From Bruce@hoult.actrix.gen.nz (Bruce Hoult) Date: Wed, 21 Sep 1994 14:48:10 +1200 (NZST) Organization: (none) resnick@uiuc.edu (Pete Resnick) writes: > On anything better than a 68010 (which is all Macs except for the classic > one) there is a wonderful little instruction: RTD. That instruction > returns, but also simultaneously deallocates space on the stack. So, what > I do is call _NMRemove (and whatever other cleanup I want to do) and then > move the _DisposePtr and an RTD instruction to the stack: Arrrrggghhh!!! There are a *lot* of PowerBook 100's out there, filled to the gills with RAM, and with a long useful life ahead of them still -- I expect to be using mine for years yet, even though I've got a PowerMac as my main machine. In case you didn't realise, the PB100 uses an original 68000 chip. -- Bruce +++++++++++++++++++++++++++ >From ludis@netcom.com (Ludis Langens) Date: Fri, 23 Sep 1994 21:25:04 GMT Organization: Netcom Online Communications Services (408-241-9760 login: guest) In article <9668AAA46BA3.6ED60@klkmac018.nada.kth.se> h+@nada.kth.se (Jon W{tte) writes: >Using a block after disposing it is BAD BAD BAD. The >Cleanup/GetTrapAddress/Jump solution is the only clean one, but >depends on the fact that DisposePtr uses register calling >conventions. The Cleanup/GetTrapAddress/Jump solution does not depend upon its target trap using register calling conventions. A Pascal style trap can also be called this way - just rearrange the stack appropriately. What it does depend upon is the register preservation and stack usage of the trap you are chaining to. It could not be used to chain to a C style function or to anything that trashes registers which your function must preserve. If you need to chain to a toolbox trap, the GetTrapAddress step can be omitted by using a trap with the Auto-pop bit set. This is a very 'official' way of jumping to a trap. (Years ago I used this trick to create code segments that self UnloadSeg-ed themselves upon returning to their caller.) Ludis Langens ludis@netcom.com --------------------------- >From fairgate@vespucci.iquest.com (Fairgate Technologies) Subject: [CWWWW] PowerPlant Tour document available Date: 23 Sep 1994 15:53:13 -0500 Organization: interQuest -- Fuel for the Mind Thanks to Marc Paquette of Metrowerks, there's now a PowerPlant Tour document on CWWWW, along with some other supporting PowerPlant material. For those of you who know what CWWWW is, these new goodies are available on the PowerPlant Central (http://www.iquest.com/~fairgate/cw/pplant.html) page. If you haven't visited CWWWW yet, come on down! CWWWW is the official CodeWarrior World-Wide Web site. IMNSHO there's quite a bit of useful information there, especially for the relatively undocumented PowerPlant class library. Point your WWW browser at http://www.iquest.com/~fairgate. Cheers, -Paul [ If you don't get a reply from me with 48hrs, please resend your message. The Mail Gods are displeased; incoming mail is sometimes silently dropped. ] -- Paul Robichaux Fairgate Technologies paul@fairgate.com Fairgate Technologies does custom Mac development. Visit the CodeWarrior WWW page at http://www.iquest.com/~fairgate. --------------------------- End of C.S.M.P. Digest **********************