qix@ihlpa.ATT.COM (Puckett) (06/14/87)
------- Below is the source and executable for an AmigaDOS handler "ID:". I wrote it to help provide a facility similar to mktemp on UNIX (tm). Since process IDs (being MsgPort addresses) are not necessarily unique on the Amiga, another method was needed for generating unique numbers. See the README file for more information. -Ed Puckett. ------- # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # README # Makefile # loader_Mount # loader.asm # ID-handler.c # ihl.uue # ih.uue # This archive created: Sun Jun 14 10:11:11 1987 cat << \SHAR_EOF > README README file for ID-handler (version 1.0 13-Jun-87) ================================================== This program and source are freely distributable, provided the file headers remain intact (i.e., my name is on them!!!). Ed Puckett accepts no responsibility for others' use of this program. ...but you shouldn't have any problems! WHAT IS THIS? ------------- ID-handler is an AmigaDOS device. It supports OPEN, CLOSE and READ. It is used to generate unique identifiers. Every time someone opens ID:, it generates a new 16 digit decimal number. This number can then be read (in ASCII) from the FileHandle obtained by opening ID:. EOF returns on all reads subsequent to reading the last digit. ID: starts with number 0000000000000000 and proceeds in sequence. You are guaranteed to get a unique number from it since it is a handler, and communication with it from two processes cannot collide. USAGE ----- You can use TYPE to access ID:, as in: TYPE ID: However, typical usage is in a program: char *gensym (sym, buf, bufsize) char *sym, *buf; int bufsize; { int symlen; BPTR fh; symlen= strlen (sym); if ( ((symlen + 1 + 16) > bufsize) || ((fh= Open ("ID:", MODE_OLDFILE)) == 0) ) return NULL; strcpy (buf, sym); Read (fh, (buf + symlen), 16); /* append digits to symbol */ buf[symlen + 16]= '\0'; Close (fh); return buf; } INSTALLATION ------------ 1. Perform the following: <uudecode ihl.uue to produce ID-handler-l> <uudecode ih.uue to produce ID-handler> Copy ID-handler-l L:ID-handler-loader Copy ID-handler L:ID-handler 2. Add to S:Startup-Sequence (do not include !'s - they denote start of line): !Mount ID: !Type >NIL: ID: 3. Add to DEVS:Mountlist (do not include !'s - they denote start of line): !ID: Handler = L:ID-handler-loader ! Stacksize = 1000 ! Priority = 5 !# 4. Reboot NOTES ON INSTALLATION --------------------- * You can skip the reboot, and just perform the "Mount" and "Dir" from the startup-sequence manually. * After the "Type", the ID-handler is loaded into the system, and the files "L:ID-handler-loader" and "L:ID-handler" will not be accessed until the next reboot. This means you may remove them from L: if you want (until next reboot). I do this because I copy L: into Ram:. * TO CHANGE THE HANDLER NAME: change "ID:" to whatever you want (e.g., "NUM:") in the following 2 files: DEVS:Mountlist (1 occurrence) S:Startup-Sequence (2 occurrences) * Feel free to shorten or otherwise change the names "ID-handler-loader" and "ID-handler". Just be sure to reflect those changes in "S:Startup-Sequence" and "DEVS:Mountlist". WHAT IS THIS SILLY "LOADER" FILE? --------------------------------- According to _The_AmigaDOS_Manual_ (Bantam Books, Feb 1986), page 291: If you write your device handler in C, you cannot use the automatic load and process creation provided by the kernel. In this case you must load the code yourself . . . . Well, I know others have gotten around this, and I did, too. However, in my "prelude" version of the handler, I noticed that the handler would take about 3 seconds to "Mount" (after first access to it). This made me very nervous - visions of wild linking through memory, etc. The loader version mounts almost immediately. Anyway, due to my (possibly unfounded) paranoia, I instead use the BCPL-like assembly module "ID-handler-loader" which LoadSeg()'s ID-handler. There are undoubtedly better ways of handling this, but this works and, for me, it is not too annoying to put up with the extra file. COMPILATION ----------- The supplied C source files were compiled with Lattice v3.03. The assembly programs were assembled using the Commodore Assembler. I use an EXECUTE file "cc" to drive the compiler. It is supplied. INQUIRIES / COMMENTS / SUGGESTIONS ---------------------------------- Ed Puckett US Mail: MIT Branch PO - PO Box 61 Cambridge, MA 02139 E Mail: ...!ihnp4!mit-eddie!mit-oz!qix SHAR_EOF cat << \SHAR_EOF > Makefile mount : loader_mount handler : loader_ID-handler obj : loader.o ID-handler.o loader_mount : handler-loader loader_ID-handler Copy ID-handler-loader L: Copy loader_ID-handler L:ID-handler Copy loader_Mount DEVS:Mountlist Mount ID: loader_ID-handler : ID-handler.o BLink FROM ID-handler.o \ TO loader_ID-handler \ LIBRARY CLIB:lc.lib+CLIB:amiga.lib ID-handler.o : ID-handler.c EXECUTE cc ID-handler loader : loader.o BLink FROM ID-handler-loader.o \ TO ID-handler-loader \ LIBRARY CLIB:amiga.lib loader.o : loader.asm Assem loader.asm -i :include -o loader.o -c w100000 SHAR_EOF cat << \SHAR_EOF > loader_Mount /* An example MOUNTLIST file enabling a 5" disk to be mounted as DF1: and an interactive serial port mounted as AUX: */ DF1: Device = trackdisk.device Unit = 1 Flags = 1 Surfaces = 2 BlocksPerTrack = 11 Reserved = 2 Interleave = 0 LowCyl = 0 ; HighCyl = 39 Buffers = 5 BufMemType = 3 # /* This is provided as an example of an alternative type of non-filing device mount. Please note that L:aux-handler is not provided, and thus this mount does not work. */ AUX: Handler = L:aux-handler Stacksize = 700 Priority = 5 # P: Handler = L:pipe-handler-loader Stacksize = 2000 Priority = 5 # ID: Handler = L:ID-handler-loader Stacksize = 1000 Priority = 5 # SHAR_EOF cat << \SHAR_EOF > loader.asm ; loader.asm INCLUDE "exec/types.i" INCLUDE "exec/exec.i" INCLUDE "libraries/dosextens.i" STRUCTURE STACKDATA,0 APTR Packet LONG ReturnVal APTR DOSBase BPTR Segment BYTE STACKDATA_SIZE XLIB: MACRO XREF _LVO\1 ENDM LINKEXE: MACRO MOVEA.L _AbsExecBase,A6 JSR _LVO\1(A6) ENDM LINKDOS: MACRO MOVEA.L DOSBase(SP),A6 JSR _LVO\1(A6) ENDM _AbsExecBase EQU 4 XLIB OpenLibrary XLIB CloseLibrary XLIB LoadSeg XLIB UnLoadSeg ;---------------------------------------------------------------------------- StartModule: DC.L (EndModule-StartModule)/4 ; for BCPL linking EntryPoint: SUBA.L #STACKDATA_SIZE,SP LSL.L #2,D1 ; convert to byte pointer MOVE.L D1,Packet(SP) CLR.L ReturnVal(SP) ; no error - for now OpenDOS: LEA DOSName(PC),A1 CLR.L D0 LINKEXE OpenLibrary MOVE.L D0,DOSBase(SP) BNE LoadCode MOVE.L #ERROR_INVALID_RESIDENT_LIBRARY,ReturnVal(SP) BRA Return LoadCode: LEA HandlerName(PC),A1 MOVE.L A1,D1 LINKDOS LoadSeg MOVE.L D0,Segment(SP) BNE CallHandler MOVE.L #ERROR_OBJECT_NOT_FOUND,ReturnVal(SP) BRA CloseDOS CallHandler: LEA SPsave(PC),A1 MOVE.L SP,(A1) ; save current SP MOVE.L Segment(SP),D0 ; BPTR to segment LSL.L #2,D0 MOVEA.L D0,A0 ; byte pointer to segment MOVE.L Packet(SP),D0 ; packet address MOVE.L D0,-(SP) ; push (not sure if safe above) ; --- Now, call the loaded handler code. ; --- It is sent the byte address of the startup packet passed to this code. JSR 4(A0) ; call first code in segment MOVEA.L SPsave(PC),SP ; restore SP UnloadCode: MOVE.L Segment(SP),D1 LINKDOS UnLoadSeg CloseDOS: MOVE.L DOSBase(SP),A1 LINKEXE CloseLibrary Return: MOVE.L ReturnVal(SP),D0 ; retrieve return value ADDA.L #STACKDATA_SIZE,SP RTS SPsave: DC.L 0 DOSName: DOSNAME HandlerName: DC.B 'L:' AProcessName: DC.B 'ID-handler',0 ; trailing definitions for BCPL linking CNOP 0,4 ; align to lonword boundary DC.L 0 ; End Marker DC.L 1 ; Global 1 DC.L EntryPoint-StartModule ; Offset DC.L 1 ; Highest Global Used EndModule: END SHAR_EOF cat << \SHAR_EOF > ID-handler.c /**************************************************************************** ** File: ID-handler.c ** Program: ID-handler - an AmigaDOS handler for generating unique names ** Version: 1.0 ** Author: Ed Puckett qix@mit-oz ** ** Copyright 1987 EpAc Software. All Rights Reserved. ** ** History: 02-Feb-87 Original Version */ #include <libraries/dos.h> #include <libraries/dosextens.h> #include <libraries/filehandler.h> #include <exec/exec.h> #include <ctype.h> /*--------------------------------------------------------------------------- ** References to system */ extern struct Library *OpenLibrary (); extern void CloseLibrary (); extern struct Task *FindTask (); extern ULONG Wait (); extern struct Message *GetMsg (); extern void PutMsg (); extern BYTE *AllocMem (); extern void FreeMem (); extern struct Library *AbsExecBase; /*--------------------------------------------------------------------------- ** These are new to the 1.2 release */ #ifndef MODE_READWRITE # define MODE_READWRITE 1004 #endif MODE_READWRITE #ifndef MODE_READONLY # define MODE_READONLY MODE_OLDFILE #endif MODE_READONLY #ifndef ACTION_END # define ACTION_END 1007 /* not really new, just missing */ #endif ACTION_END /*--------------------------------------------------------------------------- */ #define ALLOCMEM_FLAGS MEMF_PUBLIC #define ID_DIGITS 16 typedef struct opendata { char id[ID_DIGITS]; UBYTE pos; } OPENDATA; struct Library *SysBase = NULL; struct Library *DOSBase = NULL; static char ID[ID_DIGITS]; /*--------------------------------------------------------------------------- */ #define BPTRtoCptr(Bp) ((char *) ((ULONG) (Bp) << 2)) #define CptrtoBPTR(Cp) ((BPTR) ((ULONG) (Cp) >> 2)) #define ReplyPkt(pkt) PutMsg ((pkt)->dp_Port, (pkt)->dp_Link) /*--------------------------------------------------------------------------- ** handler() performs initialization, replies to startup packet, and ** dispatches incoming request packets to the apropriate functions. ** Our DeviceNode Task field is patched with our process ID so that this ** process is used for subsequent handler requests. The function exits only ** if there is some initialization error. */ void handler (StartPkt) struct DosPacket *StartPkt; { struct Task *Task; struct MsgPort *IDPort; ULONG WakeupMask, SigMask; struct DeviceNode *DevNode; struct DosPacket *pkt, *GetPkt(); unsigned i; void OpenID(), CloseID(), ReadID(); SysBase= AbsExecBase; if ((DOSBase= OpenLibrary (DOSNAME, 0)) == NULL) goto QUIT; Task= FindTask (0); IDPort= (struct MsgPort *) ((ULONG) Task + sizeof (struct Task)); ((struct Process *) Task)->pr_CurrentDir= 0; /* initial file system root */ WakeupMask= (1L << IDPort->mp_SigBit); DevNode= (struct DeviceNode *) BPTRtoCptr (StartPkt->dp_Arg3); DevNode->dn_Task= IDPort; ReplyPkt (StartPkt); for (i= 0; i < ID_DIGITS; ++i) ID[i]= '0'; LOOP: SigMask= Wait (WakeupMask); if (SigMask & WakeupMask) while ((pkt= GetPkt (IDPort)) != NULL) switch (pkt->dp_Type) { case MODE_READWRITE: OpenID (pkt); break; case MODE_NEWFILE: /* syn: ACTION_FINDOUTPUT */ pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_WRITE_PROTECTED; ReplyPkt (pkt); break; case MODE_READONLY: /* syn: MODE_OLDFILE, ACTION_FINDINPUT */ OpenID (pkt); break; case ACTION_END: CloseID (pkt); break; case ACTION_READ: ReadID (pkt); break; case ACTION_WRITE: pkt->dp_Res1= -1; pkt->dp_Res2= ERROR_WRITE_PROTECTED; ReplyPkt (pkt); break; default: pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN; ReplyPkt (pkt); } goto LOOP; QUIT: DevNode->dn_Task= NULL; /* bad if someone in process of accessing us . . . */ if (DOSBase != NULL) CloseLibrary (DOSBase); } /*--------------------------------------------------------------------------- ** GetPkt() returns the DosPacket associated with the next message on ** "port", or NULL if the port is empty. The message is removed from the ** port. A related macro, ReplyPkt(), is provided above. */ static struct DosPacket *GetPkt (port) register struct MsgPort *port; { register struct Message *msg; return ((msg= GetMsg (port)) == NULL) ? NULL : (struct DosPacket *) msg->mn_Node.ln_Name; } /*--------------------------------------------------------------------------- */ static void OpenID (pkt) struct DosPacket *pkt; { struct FileHandle *handle; OPENDATA *OpenData = NULL; unsigned i; void NextID(); if ((OpenData= (OPENDATA *) AllocMem (sizeof (OPENDATA), ALLOCMEM_FLAGS)) == NULL) { pkt->dp_Res1= 0; pkt->dp_Res2= ERROR_NO_FREE_STORE; ReplyPkt (pkt); } for (i= 0; i < ID_DIGITS; ++i) OpenData->id[i]= ID[i]; OpenData->pos= 0; NextID (); handle= (struct FileHandle *) BPTRtoCptr (pkt->dp_Arg1); handle->fh_Arg1= (LONG) OpenData; /* for identification on Read, Close */ pkt->dp_Res1= 1; pkt->dp_Res2= 0; /* for successful open */ ReplyPkt (pkt); } /*--------------------------------------------------------------------------- */ static void CloseID (pkt) struct DosPacket *pkt; { OPENDATA *OpenData; OpenData= (OPENDATA *) pkt->dp_Arg1; FreeMem (OpenData, sizeof (OPENDATA)); pkt->dp_Res1= 1; pkt->dp_Res2= 0; ReplyPkt (pkt); } /*--------------------------------------------------------------------------- */ static void ReadID (pkt) struct DosPacket *pkt; { OPENDATA *OpenData; unsigned n; OpenData= (OPENDATA *) pkt->dp_Arg1; pkt->dp_Res1= 0; if (OpenData->pos < ID_DIGITS) { if ((n= pkt->dp_Arg3) > (ID_DIGITS - OpenData->pos)) n= (ID_DIGITS - OpenData->pos); for ( ; pkt->dp_Res1 < n; ++(pkt->dp_Res1), ++(OpenData->pos)) ((char *) pkt->dp_Arg2)[pkt->dp_Res1]= OpenData->id[OpenData->pos]; } pkt->dp_Res2= 0; ReplyPkt (pkt); } /*--------------------------------------------------------------------------- */ static void NextID () { int i; for (i= ID_DIGITS - 1; (i >= 0) && (++(ID[i]) > '9'); --i) ID[i]= '0'; } SHAR_EOF cat << \SHAR_EOF > ihl.uue begin 777 ID-handler-l M #\P ! R #Z0 #( RG_P 0Y8DO M00 0J\ !$/Z (9"@"QX 1.KOW8+T "&8 XO? 'H !& %A#^@!P M(@DL;P (3J[_:B] QF .+WP #- 1@ J0_H /B*/("\ #.6(($ @ M+P +P!.J $+GH )B(O PL;P (3J[_9")O @L> $3J[^8B O 3?_ M !!.=0 !D;W,N;&EB<F%R>0!,.DE$+6AA;F1L97( $ + $ 0 _(N end SHAR_EOF cat << \SHAR_EOF > ih.uue begin 777 ID-handler M #\P $ , #S !0 0 L #Z0 /-. M5O_D2.<@("/Y ! !"ITAY "$ZY F%"/(\ $2H!G &. M0J=.N0 #!8CRU __P&@ %P@;O_\0J@ F'( ($ 2* /= 'CHB)N @B M*0 <Y8$B02- @D;@ (+Q(O*@ $+4#_^"U!_^PM0O_T3KD !84(]"KO_D M("[_Y R $&02($#1_ 0O P4J[_Y&#B+R[_]$ZY 1%B/+4#_ M\,"N__1*@&?H+R[_^&$ 1Y8CRU _^A*@&?6($ @* (<C $@0 AK "X ML+L8"&;P3OL8!@ %=@ "" 4F &P /O8 5@ ^U@ ! # M[F !8 /L8 B\N_^AA #R6(]@EB!N_^A"J ,(7P #? ! O$"\H M 1.N0 %A0CV _W8O+O_H80 Q%B/8 #_:"\N_^AA %:6(]@ /]:+R[_ MZ&$ 8I8CV _TQP_R!N_^@A0 ,(7P #? ! O$"\H 1.N0 %A0CV M_R@@;O_H0J@ #"%\ T0 0+Q O* $3KD !84(]@ /\&D<@B;O_L(T@ M"$JY !&<.+SD $3KD "$6(],WP0$3EY.=4Y6__Q(YP ,*FX ""\- M3KD !P6(\H0+G\ &8$< !@!B!L H@"$S?, !.7DYU3E;_]$*N__AP M 2\ <!$O $ZY %"/+4#_^$J 9AP@;@ (0J@ #'!G(4 $"\0+R@ !$ZY M 6%"/0J[_]" N__0,@ !!D%B!N__C1P") T_P $)%2KO_T8-X@ M;O_X0B@ $&$ 0X@;@ (("@ %.6 ($ A;O_X "1R 2)N @C00 ,0JD $"\1 M+RD !"U __Q.N0 %A0CTY>3G5.5O_\(FX ""!I !1P$2\ +P@M2/_\3KD M 84(]P 2!N @A0 ,0J@ $"\0+R@ !$ZY 6%"/3EY.=4Y6__A(YR M(&X ""UH !3__$*H QP "!N__P0* 0#( 09%(@;@ ((B@ ''00E( M M0?_XLH)C!"U"__@@;@ (("@ #+"N__AD+"!H !C1P' (F[__! I !#3P!"1 M(&X "%*H P@;O_\$"@ $%( $4 $&#&(&X "$*H ! O$"\H 1.N0 %A0 MCTS? 1.7DYU3E;__' /+4#__$JN__QK*B!N__S1_ 0$%( $( , Y M;Q0@;O_\T?P $+P ,%.N__Q@T$Y>3G4 /L !0 $ '. ! MQ@ "0 6 #@ 0 " #N@ Z0 )J F \ # M "T B8 'R !U *P . "[ JX )* !L 8X M % ?@ #( < _( /J !0 9&]S+FQI M8G)A<GD #\@ ^L $ #\@ ^D L+PXL>0 !,[P # A. MKO\Z+%].=0 +PXL>0 B;P (("\ #$ZN_RXL7TYU+PXL>0 B;P ( M3J[^VBQ?3G4O#BQY " O A.KO["+%].=2\.+'D 3.\# (3J[^ MDBQ?3G4 "\.+'D (&\ "$ZN_HPL7TYU+PXL>0 B;P (3J[^8BQ? M3G4O#BQY ")O @@+P ,3J[]V"Q?3G4 /L " $ "< MB '0 !< 2 #0 < ! /P U]/<&5N3&EB M<F%R>0 )@ $7T-L;W-E3&EB<F%R>0 (0 "7T=E=$US9P M !P E]0=71-<V< 6 )?5V%I= $0 #7T9I;F14 M87-K , )?1G)E94UE;0 !@ #7T%L;&]C365M ) /R end SHAR_EOF # End of shell archive exit 0
page@ulowell.UUCP (06/15/87)
qix@ihlpa.ATT.COM (Puckett) wrote:
>process IDs (being MsgPort addresses) are not necessarily unique on the Amiga
I bet the scheduler would be surprised to hear that! Hmmm... is that why
we sometimes see Guru Meditation messages, the scheduler tries to schedule
two processes at the same time? :-)
Of course process IDs are unique. Actually you probably want Task IDs,
which the scheduler uses.
..Bob
--
Bob Page, U of Lowell CS Dept. page@ulowell.{uucp,edu,csnet}
qix@ihlpa.ATT.COM (Puckett) (06/17/87)
In article <1384@ulowell.cs.ulowell.edu>, page@ulowell.UUCP writes: > qix@ihlpa.ATT.COM (Puckett) wrote: > >process IDs (being MsgPort addresses) are not necessarily unique on the Amiga > > Of course process IDs are unique. Actually you probably want Task IDs, > which the scheduler uses. > I was being sloppy. What I should have said was that it is possible to obtain the same process ID twice (a process could go away and another might *happen* to be allocated with the same MsgPort address). This would make it slightly unsafe to use Amiga process IDs as mktemp() does, especially for interprocess communication identifiers (like pipe names) where a process might create something and then go away. I do not know about Task IDs. Does a Task ID ever get reused from reboot to reboot? If not, then ID-handler is unnecessary, and Task IDs will work fine. -Ed Puckett.
page@ulowell.cs.ulowell.edu (Bob Page) (06/18/87)
qix@ihlpa.ATT.COM (Ed Puckett) wrote: >Does a Task ID ever get reused from reboot to reboot? If not, >then ID-handler is unnecessary, and Task IDs will work fine. They get reused. How about task ID + timestamp? That should be pretty unique. ..Bob -- Bob Page, U of Lowell CS Dept. page@ulowell.{uucp,edu,csnet}