home *** CD-ROM | disk | FTP | other *** search
-
- ABORTCOMMAND
- ~~~~~~~~~~~~
- written by Ken J. White (7th March 1988)
-
- [ED. NOTE: This useful utility is a welcome addition to the system of
- anyone fed up with those pesky software errors. Ken has also included
- the source code with his contribution, and in this description gives
- a very lucid explanation of how he programmed in MC68000 Assembly
- Language. Necessary reading for would-be programmers. Ken might
- provide us with another couple of useful commands for the next
- issue, including an intelligent ASK command which will continue
- processing a batch file after a specified period.]
-
- ************************************************************************
-
- This is a handy little utility for anyone who is developing
- software for the Amiga. It also has uses for those not inclined
- to writing software. A quite common occurrence for those testing
- programs is that the program finds itself in an endless loop,
- never returning control back to the user. For a multitasking
- computer such as the Amiga, all you have to do is write that
- task off and continue in some other task that you started up
- previously. The problem is that the misguided task will probably
- be consuming a large proportion of the microprocessor time slices,
- thus slowing everything else down (as if you had plenty of time
- waste). Rather than reboot, you can now use ABORTCOMMAND to regain
- control of a CLI task that is locked up by a faulty command. It
- also can be used in cases where a command has produced THAT well
- known requester (you know the one...... Software Error. Task
- held...... etc)! In that case you get the task back! The requestor
- remains, but is totally inactive, thus preventing that annoying
- behaviour of the system ominously replacing it at the front in the
- top left-hand corner every time you put a disk in a drive.
-
- There are, however, limitations on the use of ABORTCOMMAND.
- First, there must be either Workbench or another CLI active in
- order to use ABORTCOMMAND. Thus it is common sense to have at
- least two processes (Workbench and/or CLIs) active before any
- programs are tested. ABORTCOMMAND can be accessed from either
- a CLI or Workbench. Second, ABORTCOMMAND can be used to abort
- CLI commands ONLY. It cannot be used to abort Workbench programs,
- tasks in general, or interrupts. To abort these would require
- information that is not readily available to the user. This is
- especially true with Workbench programs. Third, ABORTCOMMAND
- can only be used where multitasking and interrupts have not
- been disabled by the faulty command or where a guru has not been
- generated. More general, ABORTCOMMAND cannot be used when the
- whole system has frozen, crashed, or died some other horrible
- death. Fourth, ABORTCOMMAND does not perform any clean-up
- operations except for what DOS normally does when a command
- exits. Any memory, signals, traps, etc, that the command has
- allocated will remain allocated. Any files, devices, windows,
- libraries, etc, that the command opens will remain open. Any
- tasks, processes, interrupts, etc, that have the command has
- created, unless they can remove themselves, will remain. An
- example was given above where an inactive requester remains.
- Finally, the use of ABORTCOMMAND should NEVER be regarded as
- completely safe. It will generally be operating in an unknown
- environment where the effects of aborting a command is quite
- unpredictable. Fortunately, most critical operations will be
- performed with multitasking disabled, so that you will be
- protected from the worst effects of unpredictability.
-
- The use of ABORTCOMMAND is quite straightforward. Simply
- type it as a CLI command or double-click it's icon. A window
- will open and you will be asked to input the CLI number of the
- command to abort. For commands initiated by RUN, this is the
- CLI number generated by RUN, not of the CLI in which RUN was
- performed. The name of the command will be printed and you will
- be asked whether you wish to abort it. Type "y","Y","yes", or
- in fact anything that starts with a "y" or "Y", and the named
- command will be aborted unless some problem is found. The program
- will then exit. If the CLI number input was found to be invalid,
- or you typed something that didn't start with "y" or "Y" when
- asked whether to abort, or some other problem was encountered, you
- will be asked if you wish to exit. Again "y","Y" as the first
- character will cause the program to exit, otherwise it will
- restart by asking you to input a CLI number. On exit, regardless
- of whether a command was aborted or not, the window will be closed
- and the return code will be zero (no error). Errors that prevent
- the window from being opened will generate a return code of 20
- (fail). The aborted command will generate a return code of 100 but
- no message.
-
-
-
- Technical Information
- ~~~~~~~~~~~~~~~~~~~~~
-
- This section is to give programmers and hackers in general more
- information on how this utility operates and give a little insight
- on other possible uses. Because these other uses are not currently
- implemented, I have supplied the source code (MC68000 Assembly
- Language) so that modifications may be made. An attempt was made
- to make this code flexible so that modifications will not be too
- difficult. The code has not been liberally interspersed with
- comments, however, I believe that I have supplied sufficient
- information to allow anyone who knows what they are doing to
- easily understand and modify the code.
-
- The code consists of four sections: AbortCommand, function,
- subroutines, and donated_segment.
-
- "AbortCommand" performs the initialisation procedure. This
- consists of allocating and clearing 320 bytes of stack space,
- obtaining the address of our task, then testing whether we are
- running under Workbench or a CLI. If under Workbench, we wait for,
- then obtain the message that Workbench has sent us. The address of
- the predecessor segment to donated_segment is obtained using the
- label, external_code, to identify the segment, donated_segment.
- (This will be explained in greater detail below.). The DOS library
- is then opened and if under CLI, the default output file handle is
- obtained (for error messages). The CON: window is then opened.
- Subroutine, function, (fully explained below) is performed.
- "AbortCommand" also performs the finalisation procedure of closing
- the window, closing the DOS library, and if run from Workbench,
- replying to its message. Stack space is deallocated then we RTS
- back to DOS. Open library and window errors are also handled.
-
- "function" performs the real magic. First, it clears D7, which
- is used internally, as a set of flags. Then, it asks for the CLI
- number of the command to abort. All message output (except the
- command name string) is handled the same way. The subroutine,
- output_string, uses a message base address (in A0) and a message
- number (in D0) to output a variable length null-terminated string
- to the file handler (in D1) (the window). The message base address
- corresponds to the start of the first message which is message
- number 1. The subroutine, input_cli_num, inputs a decimal or
- hexadecimal number of up to 8 digits. The use of the "$" character
- immediately before the number (ie, no spaces) distinguishes a
- hexadecimal from a decimal number. This allows the subroutine to
- be used for inputing such data as task addresses, etc. The
- subroutine converts the ASCII string to a binary value and returns
- the result (or zero if invalid) in D0. "function" then disables
- interrupts then tests the existance of the requested CLI. If it
- exists, the task address of the CLI is determined and placed in
- A1. This is compared with our task address. If different, the
- Ready and Wait task lists are scanned in search of the task. If
- not found, bit 30 of D7 will be set. If found in the Wait list,
- bit 31 of D7 will be set (although this is not subsequently used).
- Subroutine, command_name, is then performed. This routine tests
- whether a command is currently loaded, if so, it copies the name
- string to our input buffer, interrupts are enabled and the copied
- name string is outputed. Otherwise, bit 29 of D7 is set, then
- interrupts are enabled. "function" then asks whether you wish to
- abort the command. (The function of subroutine, confirm_abort, was
- adequately explained above.). Interrupts are then disabled.
- Because of the period of enabled interrupts (and therefore,
- multitasking) we cannot trust any of the information obtained
- earlier. The CLI number is used to redetermine the task address
- which is verified with the previously determined task address.
- If it verifies as the same, the Ready and Wait task lists are
- rescanned. If the task is not found, the state of bit 30 of D7 is
- reversed. I try to take into consideration all possibilities,
- including that of the task inadvertently removing itself from the
- task lists. However, because the environment is unknown, we must
- view tasks, that are not in the lists, with suspicion. The point
- is that we base our decision of whether or not to abort it on the
- result of both task list scans. A change, especially where the
- task has moved back into the lists, suggests that the task may be
- under external control and best left alone. Bit 30 of D7 is
- tested. If 0, we assume the task has not moved (we fully expect
- the task to interchange between Ready, Run, and Wait states and
- thus ignore such changes except that bit 31 of D7 correctly
- reflects the state), and if the task is not in the lists, we set
- bit 30 of D7. "function" then obtains the address of the tail
- segment of the command to abort, the stack pointer to the DOS
- supplied return address, and the stack pointer to the task's
- stored stack frame. In each case, a test is made to assure that
- the command has not exited or is not in the process of exiting.
- The address associated with the label, external_pc_cli, is
- obtained and stored for later use. This address is, eventually,
- to become the command's new program counter. Note that the
- label corresponds to the same address as label, external_code.
- However, I chose to use different labels for greater flexibility
- in case modifications are made. The segment, donated_segment, is
- then removed from our code's segment list and added to the tail
- of the segment list of the command to abort. (An explanation of
- why this is done is best deferred till later.). All the command
- task's registers are transferred from the stored stack frame to
- a data storage area within segment, donated_segment, then the
- stored program counter is replaced and the stored status
- register is cleared. The new stack pointer, which points to the
- DOS supplied return address, is not stored within the task's
- context but, rather, within the segment, donated_segment. This
- was done to maintain flexibility should this code every be
- modified. Finally the task is transferred to the TaskReady list
- then the interrupts are enabled. The next time the task regains
- the microprocessor, it will exit back to DOS. If any problems
- were encountered along the way you will be asked if you wish to
- exit. The subroutine, confirm_exit, is essentially the same as
- subroutine, confirm_abort, except that a different message is
- generated. "function" will either exit or restart from label,
- function.
-
- "subroutines" contain all the miscellaneous subroutines used
- by our code. I believe an adequate description has been given.
- If you wish to find out more, you will have to look at the code
- itself.
-
- "donated_segment" is the segment that is transferred to the
- command's segment list. It contains the code to allow the
- command to exit back to DOS. It also contains all of the task's
- original registers and the task's new stack pointer. The task's
- new stack pointer is utilised by the code so that at the entry
- point, the entire task context is available, which it would not
- have been if the stack pointer were altered by "function".
- Because the command is aborted by altering the task's program
- counter and allowing multitasking to take its course, thereby
- forcing it to exiting via external_pc_cli, which is part of our
- context, I had to consider the possibility of our program
- exiting before the command to abort regains the microprocessor.
- This would cause the program counter to point to invalid code,
- resulting in a system crash. I decided to remove the segment,
- "donated_segment", from our context and add it the context of
- the command. By disowning the segment, our code can exit at any
- time with a clear conscience. When the aborted command exits,
- DOS will free the memory associated with the segment as if it
- were originally loaded as part of the command.
-
- Although it is possible to modify the code so that it will
- abort Workbench objects, tasks in general, interrupt handlers
- and servers, etc, one application that I find tantalizing is to
- investigate locked up commands "on the fly", ie, while it is
- actually running. By modifying ABORTCOMMAND and using your
- favourite debugger as if you are debugging your modified
- ABORTCOMMAND, you can invesigate the state of the locked up
- command at some instant during its execution, perhaps following
- its progress in nearly real time (I can't say what can actually
- be done since I don't know the nature of your debugger). By
- setting up break-points within your modified ABORTCOMMAND, you
- can look at the stored registers within segment, donated_segment,
- to see exactly what is happening. In such a case it may be
- desirable to assemble section, donated_segment, separately
- using the symbol dump option (this is why each register storage
- location has its own label even though the labels are not
- referenced at all by my code). A more sophisticated way would
- be to modify ABORTCOMMAND so that it lists all the register
- values to a window. To modify ABORTCOMMAND to perform debugging
- operations, do not allow the code to transfer "donated_segment"
- or modify the task's stored stack frame. Also, remember that
- interrupts are disabled throughout most of the code's operation,
- so you will be well advised to enable interrupts before doing
- anything that requires multitasking. I hope you find this
- information useful and that you enjoy using ABORTCOMMAND.
-
- Ken White
- ~~~~~~~~~
-
- THE END
- ~~~~~~~
-
-