From: jesup@cbmvax.commodore.com (Randell Jesup)
Newsgroups: comp.sys.amiga.programmer
Subject: Re: A few Handler/FileSys Q's (Mod.Long.)
Date: 19 Dec 92 01:22:31 GMT
Reply-To: jesup@cbmvax.commodore.com (Randell Jesup)
Organization: Commodore, West Chester, PA
Keywords: handler filesystem packets Amiga DOS AmigaDOS lock FileLock

bombadil@diku.dk (Kristian Nielsen) writes:
>Now, say the handler has to put up a requester. This is done in the
>usual way using EasyRequest() or whatever. The usual approach would
>be to have some code like
>
>	EasyRequest(winptr, &myrequest);
>	WaitPort(myicdmport);
>
>However, this would lock out *ANY* access to the file system while the
>requester was being displayed. To avoid this, the WaitPort() is replaced
>by a coroutine context switch to the coroutine doing the central handler
>loop. Later, when the requester is satisfied, the coroutine doing the
>EasyRequest() will be resumed.

	Well, actually the filesystem almost never puts up requesters itself -
that's normally done by dos (using ErrorReport()).

>The usual way to implement coroutines involve having seperate stacks for
>each coroutine, swapping them when nessesary. The ROM file systems may
>do it differently, we'd need one of the commodore gurus to give the
>details.

How The Amiga FS Works (preview showing, by invitation only):

	Yes, they're coroutines (BCPL ones).  Anything that blocks in exec
(i.e. Wait()) will stop all of them.  Internally, it switches around between
them as needed (no preemption).  CallCo() will swap to a coroutine (much like
jsr), WaitCo() returns a results to the parent (much like rts).  One important
difference with subroutines is that the coroutines maintain their own stacks
and state.  ResumeCo() is basically a branch to a coroutine (as if it had
been CallCo'd by your caller - much like exiting a subroutine with jmp
some_other_subrutine).  There are various other utility functions, like
StartCo, KillCo, CreateCo, etc.

	Each open filehandle is a coroutine.  The master coroutine CallCo()'s
it when it gets a packet or when IO comes back.  Note that this is where the
stack-based state information of the coroutine come into play - a filehandle
coroutine does IO by queuing a request, and calling WaitCo().  The disk
read/write coroutine pulls things from the queue and gets woken up when IO
is done.  When an IO is complete and verified, it notes which coroutine is
waiting for the IO to complete (can be a list), and ResumeCo()'s that 
coroutine.  Since the coroutine has a stack, it continues at the point after
the WaitCo with whatever it was doing, now knowing the IO was complete.
Note that the master coroutine doesn't CallCo() an active filehandle coroutine,
it queues the packet for later handling.

	If this seems simple, I guarantee you, IT'S NOT.  It's mind-warping
and arcane when you need to care about the coroutines (but easy and
straightforward when you don't).  A lot of state information becomes 
automatic, without having to build a (massive) explicit state machine.  I
burnt out a lot of brain cells figuring out how to handle locking of updates
to hash chains in this setup, since this required major interactions between
coroutines.  The end result was simple, but it was a bitch to figure out.

>ixemul.library by Marcus Wild). For this reason, lock->fl_Task MUST
>remain valid at all times.

	Correct.

>>3) As a filesystem, if a volume has just been inserted into the device you're
>>managing, and you grab the locks from the dol_LockList, can you Forbid(), go
>>through and change the fl_Task field of all the locks to yourself, then Permit()
>>so that any further use of the active FileLocks will be directed to you?
>
>(minor detail: in 2.0 you use LockDoslist() / UnlockDoslist() instead of
>Forbid() / Permit(). )

	Correct, I missed that in my last post.  If you must work under 1.3,
please make the LDL/ULDL calls conditional.

>I don't think this should be done. I can hardly imagine it's 'legal',
>for one. Just imagine the instant disaster that would result if you
>somehow mixed of a volume belonging to a completely alien file system!
>Anyway, it shouldn't be nessesary to do this.

	You need to make SURE it's the same volume (date AND name AND
DLT_VOLUME).  When you find it, you must change dol_Task in the volumenode,
and the fl_Task's of all of the locks on the locklist.

>>4) If, again as a filesystem, I get an argument FileLock for a volume I am
>>no longer managing (volume was ejected from my device), can I, upon inspection
>>of the DosList finding a non-NULL dol_Task field, send the packet onto

>Again, the best thing to do would be to ask for the volume to be
>inserted in the right drive.

	Fail the packet (note: some packets use -1 for error (read/write/
seek/setfilesize), some use 0 (end(close))), with an ERROR_DEVICE_NOT_MOUNTED.
Dos will put up the Please insert xxx: in device yyy: for you.

>[Aside: This asking the user to move the disk might seem unfriendly
>(though it seldom occurs in practice; perhaps dos.library does some
>magic with ASSIGNed names?).

	Since Assigns are locks, not filehandles, they can move with the
disk from filesystem to filesystem.  Filehandles, being coroutines, can't.

-- 
To be or not to be = 0xff
-
Randell Jesup, Jack-of-quite-a-few-trades, Commodore Engineering.
{uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com  BIX: rjesup  
Disclaimer: Nothing I say is anything other than my personal opinion.
Newsgroups: comp.sys.amiga.programmer