home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / tools / system / shutdown / devwatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  10.8 KB  |  534 lines

  1. /*
  2. **    Shutdown 2.0 package, DevWatch.c module
  3. **
  4. **    Copyright © 1992 by Olaf `Olsen' Barthel
  5. **        All Rights Reserved
  6. */
  7.  
  8. #include "ShutdownGlobal.h"
  9.  
  10.     /* The following actions will be blocked since they
  11.      * generate write-accesses to a device.
  12.      */
  13.  
  14. #define ALL_BLOCK_FLAGS        ((1 << CMD_READ) | (1 << CMD_WRITE) | (1 << TD_SEEK) | (1 << TD_FORMAT) | (1 << TD_RAWREAD) | (1 << TD_RAWWRITE))
  15.  
  16.     /* This piece of code gets wedged between the device BeginIO()
  17.      * vector and the actual routine associated with it. Before the
  18.      * call finally lands in the BeginIO() routine it has to pass
  19.      * through our blocking routine.
  20.      */
  21.  
  22. struct BeginIOWedge
  23. {
  24.     UWORD    Jsr;        /* The MC680x0 `JSR ea' opcode. */
  25.     APTR    BlockRoutine;    /* The destination address. */
  26.  
  27.     UWORD    Jmp;        /* The MC680x0 `JMP ea' opcode. */
  28.     APTR    BeginIO;    /* The destination address. */
  29. };
  30.  
  31.     /* This is a big wedge entry, it stores the effective
  32.      * BeginIO() wedge and pointers to the base address of
  33.      * the device which was patched. Also included is a
  34.      * wedge for the Expunge() vector which prevents the
  35.      * device from getting expunged before the wedges
  36.      * are removed.
  37.      */
  38.  
  39. struct BigWedge
  40. {
  41.     struct BigWedge        *Next;        /* Next entry in list. */
  42.     struct Device        *Device;    /* The patched device. */
  43.  
  44.     APTR             OldExpunge;    /* The old expunge vector. */
  45.  
  46.     struct BeginIOWedge     DevBeginIO;    /* The BeginIO() wedge. */
  47.     struct Wedge         DevExpunge;    /* The Expunge() wedge. */
  48. };
  49.  
  50.     /* The list of wedges installed and the access semaphore. */
  51.  
  52. STATIC struct SignalSemaphore     WedgeSemaphore;
  53. STATIC struct BigWedge        *WedgeChain;
  54.  
  55.     /* Local data. */
  56.  
  57. STATIC struct Task        *DeviceWatchTask;
  58.  
  59.     /* Local routines for this module. */
  60.  
  61. STATIC VOID __saveds        DeviceWatchServer(VOID);
  62.  
  63.     /* DeviceWatchServer():
  64.      *
  65.      *    This is a watchdog task which continuously monitors
  66.      *    device IO activity.
  67.      */
  68.  
  69. STATIC VOID __saveds
  70. DeviceWatchServer()
  71. {
  72.     struct MsgPort *TimePort;
  73.  
  74.         /* Initialize the wedge list access semaphore. */
  75.  
  76.     InitSemaphore(&DeviceWatchSemaphore);
  77.  
  78.         /* Create the timer reply port. */
  79.  
  80.     if(TimePort = CreateMsgPort())
  81.     {
  82.         struct timerequest *TimeRequest;
  83.  
  84.             /* Create the timer IO request. */
  85.  
  86.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  87.         {
  88.                 /* Open the timer.device. */
  89.  
  90.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  91.             {
  92.                 BYTE    HadAccesses    = TRUE,
  93.                     AllClear    = FALSE;
  94.                 ULONG    SignalSet;
  95.  
  96.                     /* Provide handshake signal. */
  97.  
  98.                 Signal(HandlerProcess,SIG_HANDSHAKE);
  99.  
  100.                     /* Go into loop... */
  101.  
  102.                 do
  103.                 {
  104.                         /* Gain access to the wedge list. */
  105.  
  106.                     ObtainSemaphore(&DeviceWatchSemaphore);
  107.  
  108.                         /* Is the shutdown process up and running? */
  109.  
  110.                     if(MainProcess)
  111.                     {
  112.                             /* Did any IO activity take place and does
  113.                              * it still make sense to notify the
  114.                              * shutdown process?
  115.                              */
  116.  
  117.                         if(DeviceInUse != HadAccesses && !GlobalBase -> DevShutdown)
  118.                         {
  119.                                 /* Did no access take place in
  120.                                  * the last few seconds?
  121.                                  */
  122.  
  123.                             if(!DeviceInUse)
  124.                                 AllClear = TRUE;
  125.                             else
  126.                                 AllClear = FALSE;
  127.  
  128.                                 /* Remember the current state. */
  129.  
  130.                             DeviceProbablyInUse = DeviceInUse;
  131.  
  132.                                 /* Notify the shutdown process. */
  133.  
  134.                             Signal(MainProcess,SIG_NOTIFY);
  135.                         }
  136.  
  137.                             /* Is the system just about to go down
  138.                              * and IO activity increases? If so,
  139.                              * notify the shutdown process.
  140.                              */
  141.  
  142.                         if(!DeviceInUse && !HadAccesses && GlobalBase -> DevShutdown)
  143.                             Signal(MainProcess,SIG_NOTIFY);
  144.                     }
  145.  
  146.                         /* Remember previous state. */
  147.  
  148.                     HadAccesses = DeviceInUse;
  149.  
  150.                         /* Clear the flag. */
  151.  
  152.                     DeviceInUse = FALSE;
  153.  
  154.                         /* Release the access semaphore. */
  155.  
  156.                     ReleaseSemaphore(&DeviceWatchSemaphore);
  157.  
  158.                         /* Set up the timer IO request. */
  159.  
  160.                     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  161.                     TimeRequest -> tr_time . tv_secs    = 1;
  162.                     TimeRequest -> tr_time . tv_micro    = 500000;
  163.  
  164.                         /* Is the shutdown process running? */
  165.  
  166.                     if(MainProcess)
  167.                     {
  168.                             /* Start the timer. */
  169.  
  170.                         SendIO(TimeRequest);
  171.  
  172.                             /* Clear our notification signal. */
  173.  
  174.                         SetSignal(0,SIG_NOTICE);
  175.  
  176.                             /* Wait for timer or notification. */
  177.  
  178.                         SignalSet = Wait(SIG_TIME | SIG_NOTICE);
  179.  
  180.                             /* IO activity notification signal? */
  181.  
  182.                         if(SignalSet & SIG_NOTICE)
  183.                         {
  184.                                 /* Did we give permission to quit? */
  185.  
  186.                             if(AllClear)
  187.                             {
  188.                                     /* Change the flags. */
  189.  
  190.                                 DeviceInUse        = TRUE;
  191.                                 DeviceProbablyInUse    = TRUE;
  192.                                 AllClear        = FALSE;
  193.  
  194.                                     /* Notify the shutdown process. */
  195.  
  196.                                 Forbid();
  197.  
  198.                                 if(MainProcess)
  199.                                     Signal(MainProcess,SIG_NOTIFY);
  200.  
  201.                                 Permit();
  202.                             }
  203.                         }
  204.                     }
  205.                     else
  206.                         SendIO(TimeRequest);
  207.  
  208.                         /* Wait for timer. */
  209.  
  210.                     WaitIO(TimeRequest);
  211.                 }
  212.                 while(!CheckSignal(SIG_KILL));
  213.  
  214.                     /* Close the timer. */
  215.  
  216.                 CloseDevice(TimeRequest);
  217.             }
  218.  
  219.                 /* Free the timer request. */
  220.  
  221.             DeleteIORequest(TimeRequest);
  222.         }
  223.  
  224.             /* Delete the timer reply port. */
  225.  
  226.         DeleteMsgPort(TimePort);
  227.     }
  228.  
  229.         /* Disable multitasking. */
  230.  
  231.     Forbid();
  232.  
  233.         /* Ring back. */
  234.  
  235.     Signal(HandlerProcess,SIG_HANDSHAKE);
  236.  
  237.         /* Remove ourselves. */
  238.  
  239.     RemTask(DeviceWatchTask = NULL);
  240. }
  241.  
  242.     /* WedgeSetup():
  243.      *
  244.      *    Install the device BeginIO() wedges and start the watchdog.
  245.      */
  246.  
  247. BYTE
  248. WedgeSetup()
  249. {
  250.     struct DosList *DosEntry;
  251.  
  252.         /* Set up the wedge list access semaphore. */
  253.  
  254.     InitSemaphore(&WedgeSemaphore);
  255.  
  256.         /* Create the watchdog. */
  257.  
  258.     DeviceWatchTask = CreateTask(GetString(MSG_DEVTASKNAME_NAME),50,(APTR)DeviceWatchServer,4000);
  259.  
  260.         /* Wait for ringback. */
  261.  
  262.     Wait(SIG_HANDSHAKE);
  263.  
  264.         /* Did we succeed in creating it? */
  265.  
  266.     if(DeviceWatchTask)
  267.     {
  268.             /* Lock the doslist for device reading. */
  269.  
  270.         if(DosEntry = LockDosList(LDF_DEVICES | LDF_READ))
  271.         {
  272.                 /* Scan for devices... */
  273.  
  274.             while(DosEntry = NextDosEntry(DosEntry,LDF_DEVICES | LDF_READ))
  275.             {
  276.                     /* Does it have a filesystem process attached? */
  277.  
  278.                 if(TypeOfMem(DosEntry -> dol_Task))
  279.                 {
  280.                         /* Is the device startup valid. */
  281.  
  282.                     if(TypeOfMem(BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup)))
  283.                     {
  284.                         struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup);
  285.  
  286.                             /* Is the startup message valid? If so,
  287.                              * create a new device list entry.
  288.                              */
  289.  
  290.                         if(TypeOfMem(BADDR(FSSM -> fssm_Device)) && TypeOfMem(BADDR(FSSM -> fssm_Environ)))
  291.                             NewWedge(&((UBYTE *)BADDR(FSSM -> fssm_Device))[1]);
  292.                     }
  293.                 }
  294.             }
  295.  
  296.                 /* Release the lock. */
  297.  
  298.             UnLockDosList(LDF_DEVICES | LDF_READ);
  299.         }
  300.  
  301.             /* Return success. */
  302.     
  303.         return(TRUE);
  304.     }
  305.     else
  306.         return(FALSE);
  307. }
  308.  
  309.     /* DeleteWedges():
  310.      *
  311.      *    Disable all the wedges installed by NewWedge().
  312.      */
  313.  
  314. VOID
  315. DeleteWedges()
  316. {
  317.     struct BigWedge    *Wedge;
  318.  
  319.         /* Tell the watchdog task to shut down. */
  320.  
  321.     Signal(DeviceWatchTask,SIG_KILL);
  322.  
  323.         /* Wait for ringback. */
  324.  
  325.     Wait(SIG_HANDSHAKE);
  326.  
  327.         /* Disable multitasking. */
  328.  
  329.     Forbid();
  330.  
  331.         /* Obtain a lock on the wedge list. */
  332.  
  333.     ObtainSemaphore(&WedgeSemaphore);
  334.  
  335.     Wedge = WedgeChain;
  336.  
  337.         /* Walk down the list... */
  338.  
  339.     while(Wedge)
  340.     {
  341.             /* Redirect the `JSR ea' to the original BeginIO()
  342.              * routine.
  343.              */
  344.  
  345.         Wedge -> DevBeginIO . Jsr        = JMP_ABS;
  346.         Wedge -> DevBeginIO . BlockRoutine    = Wedge -> DevBeginIO . BeginIO;
  347.  
  348.             /* Make the expunge wedge use the original routine. */
  349.  
  350.         Wedge -> DevExpunge . Address        = Wedge -> OldExpunge;
  351.  
  352.             /* Get to the next list entry. */
  353.  
  354.         Wedge = Wedge -> Next;
  355.     }
  356.  
  357.         /* Flush the caches. */
  358.  
  359.     CacheClearU();
  360.  
  361.         /* Reenable multitasking. */
  362.  
  363.     Permit();
  364.  
  365.         /* Release the lock on the list. */
  366.  
  367.     ReleaseSemaphore(&WedgeSemaphore);
  368. }
  369.  
  370.     /* NewWedge(STRPTR DeviceName):
  371.      *
  372.      *    Install a new BeginIO()/Expunge() wedge.
  373.      */
  374.  
  375. VOID
  376. NewWedge(STRPTR DeviceName)
  377. {
  378.     struct BigWedge    *Wedge;
  379.     BYTE         IsInstalled = FALSE;
  380.     struct Device    *Device;
  381.  
  382.         /* Gain access to the wedge list. */
  383.  
  384.     ObtainSemaphore(&WedgeSemaphore);
  385.  
  386.     Wedge = WedgeChain;
  387.  
  388.         /* Search the list... */
  389.  
  390.     while(Wedge)
  391.     {
  392.             /* Does the device in question have a valid name? */
  393.  
  394.         if(Wedge -> Device -> dd_Library . lib_Node . ln_Name)
  395.         {
  396.                 /* Is there already a wedge in place for
  397.                  * this device?
  398.                  */
  399.  
  400.             if(!strcmp(Wedge -> Device -> dd_Library . lib_Node . ln_Name,DeviceName))
  401.             {
  402.                     /* Looks like it. */
  403.  
  404.                 IsInstalled = TRUE;
  405.  
  406.                 break;
  407.             }
  408.         }
  409.  
  410.             /* Get to the next list entry. */
  411.  
  412.         Wedge = Wedge -> Next;
  413.     }
  414.  
  415.         /* Has this device been patched already? */
  416.  
  417.     if(!IsInstalled)
  418.     {
  419.             /* Disable multitasking and interrupt processing. */
  420.  
  421.         Disable();
  422.  
  423.             /* Try to find the device in the list. */
  424.  
  425.         if(Device = (struct Device *)FindName(&SysBase -> DeviceList,DeviceName))
  426.         {
  427.                 /* Allocate a new big wedge. */
  428.  
  429.             if(Wedge = (struct BigWedge *)AllocMem(sizeof(struct BigWedge),MEMF_PUBLIC | MEMF_CLEAR))
  430.             {
  431.                     /* Set up the head and remember the device base address. */
  432.  
  433.                 Wedge -> Next                = WedgeChain;
  434.                 Wedge -> Device                = Device;
  435.  
  436.                     /* Install the new redirection code. */
  437.  
  438.                 Wedge -> DevBeginIO . Jsr        = JSR_ABS;
  439.                 Wedge -> DevBeginIO . BlockRoutine    = BlockBeginIO;
  440.                 Wedge -> DevBeginIO . Jmp        = JMP_ABS;
  441.                 Wedge -> DevBeginIO . BeginIO        = SetFunction(Device,DEV_BEGINIO,(APTR)&Wedge -> DevBeginIO);
  442.  
  443.                     /* Patch the expunge function. */
  444.  
  445.                 Wedge -> DevExpunge . Command        = JMP_ABS;
  446.                 Wedge -> DevExpunge . Address        = NewDevExpunge;
  447.  
  448.                 Wedge -> OldExpunge            = SetFunction(Device,-18,(APTR)&Wedge -> DevExpunge);
  449.  
  450.                     /* Put the wedge into the list. */
  451.  
  452.                 WedgeChain = Wedge;
  453.  
  454.                     /* Flush the caches. */
  455.  
  456.                 CacheClearU();
  457.             }
  458.         }
  459.  
  460.             /* Reenable multitasking and interrupt processing. */
  461.  
  462.         Enable();
  463.     }
  464.  
  465.         /* Release the access lock. */
  466.  
  467.     ReleaseSemaphore(&WedgeSemaphore);
  468. }
  469.  
  470.     /* DevExpunge(register __a6 struct Device *Device):
  471.      *
  472.      *    Modified expunge routine.
  473.      */
  474.  
  475. ULONG __asm
  476. DevExpunge(register __a6 struct Device *Device)
  477. {
  478.         /* Clear the delayed expunge flag. */
  479.  
  480.     Device -> dd_Library . lib_Flags &= ~LIBF_DELEXP;
  481.  
  482.         /* Don't unload the device. */
  483.  
  484.     return(NULL);
  485. }
  486.  
  487.     /* BlockRoutine(register __a1 struct IOStdReq *Request):
  488.      *
  489.      *    This routine is called before IO processing
  490.      *    actually gets to the BeginIO() vector. It is
  491.      *    to notify the watchdog of IO activity and
  492.      *    blocks IO processing in case the system is
  493.      *    to go down.
  494.      */
  495.  
  496. VOID __asm
  497. BlockRoutine(register __a1 struct IOStdReq *Request)
  498. {
  499.     UWORD Command = Request -> io_Command & ~TDF_EXTCOM;
  500.  
  501.         /* Is this a likely write command? */
  502.  
  503.     if(Command < 32)
  504.     {
  505.             /* Is this a write access? */
  506.  
  507.         if((1L << Command) & ALL_BLOCK_FLAGS)
  508.         {
  509.                 /* Change the access flag. */
  510.  
  511.             ObtainSemaphore(&DeviceWatchSemaphore);
  512.  
  513.             DeviceInUse = TRUE;
  514.  
  515.             ReleaseSemaphore(&DeviceWatchSemaphore);
  516.  
  517.                 /* Is the system going down? If so,
  518.                  * block until the lock is released.
  519.                  */
  520.  
  521.             if(GlobalBase -> DevShutdown)
  522.             {
  523.                 ObtainSemaphoreShared(&GlobalBase -> DevBlockLock);
  524.  
  525.                 ReleaseSemaphore(&GlobalBase -> DevBlockLock);
  526.             }
  527.  
  528.                 /* Notify the watchdog. */
  529.  
  530.             Signal(DeviceWatchTask,SIG_NOTICE);
  531.         }
  532.     }
  533. }
  534.