karl@sugar.UUCP (Karl Lehenbauer) (09/05/87)
The question often comes up on the net, "How can I kill my Amiga tasks?" or more often, "Why can't I kill my Amiga tasks?". The problem, of course, is resource tracking, or more specifically the lack of support for it under AmigaDOS. We've been told that there would be too much overhead to implement this. I think most of us tend to discount that as we end up having to write equivalent (and tricky) code in each of our programs anyway. There is a case to be made for the former position, though, as the existing OS routines (memory alloc, etc.) are quite speedy and it would undeniably increase overhead to add resource tracking. Anyway, I think any solution should be compatible with existing code (as much as possible possible), easy to use and would be most likely to succeed if it didn't require changing the operating system. Peter da Silva (sugar!peter) and I were quite surprised recently when we found out that Mac windows all behave in a manner that is analogous to the Amiga's simple refresh windows. What that means is that every time your program's window gets resized or has something moved from in front of it, it has to redraw part or all of the window. This makes even "Hello, world" type programs hard to write. The Maccians get around this by using libraries as a front-end to the toobox calls to provide some enhanced capabilities that aren't present in the toolbox itself. We should do that, too. The memory allocation problem can be solved by using AllocRemember (Thanks, Peter, for showing me this). Library routines would front-end calls to create message ports and such. The library routines would keep track of what things need to be cleaned up on termination and how to do the cleanup in addition to making the system calls to perform the specified operations. The _main (for C people) startup code would set up to receive a software interrupt on the various control keys. The interrupt would call the code that cleans everything up. All a programmer would have to do to use this is to link from the new resource-tracking library. It is even possible for the routines in this new library to have the same names as their non-resource- tracking counterparts. The existing names, after all, are just the names of assembly routines that call an offset to A6 after playing with the stack and registers. You give those routines new names and call them, via their new names, from the new resource tracking routines that bear the original names. If one were to do the same for RemTask, one wouldn't need to explicitly call any special resource tracking code at all! (Peter came up with this part. I think it'll work.) Yes, it is stinky that the resource tracking code will have to be linked into every program that makes use of it rather than just being part of the OS. It mightn't neccessarily increase the size of programs a whole lot, though, as it could be implemented as a shared, reentrant, dynamically-loaded library like the ones in LIBS:. --- Now I'd like to end my posting, which I hope has provided a positive and technical contribution to this newsgroup, with a remark that postings about the inappropriateness of other postings, please-don't- post-about-this postings, postings about the danger to the net posed by all the garbage postings and so on consume net bandwidth too, and often create the destructive meta discussions warned about in the netnews new user docs. Flaming, also, increases net bandwidth, as few people are going to be willing to undergo a thorough, public charcoaling without making some sort of public reply. For most people, to not do so feels like tacit surrender to the flamer, with additional scorching caused by the provocative language that characterizes such flames. -- ...!soma!uhnix1!sugar!karl "Life is wasted on the living." - Z.B. IV
dillon@CORY.BERKELEY.EDU (Matt Dillon) (09/09/87)
Interesting proposal. Let's put aside the memory allocation tracking for the moment and first concentrate on other resources. All other system resources are either device or library oriented, or special EXEC calls. For instance, to use DOS file handles you must open the DOS library; to use the SERIAL.DEVICE, you must open the serial device. To use Intutition you must open the intuition library. To allocate resources you must make the proper EXEC calls. Assuming the libraries and devices did their own tracking of which OpenLibrary/OpenDevice is associated with an IO request, all EXEC would have to do is keep a list of all currently open libraries and devices for a specific task. Even if a task forgets to close a library, EXEC would have the list and would close the library for the task (the library/device then closing associated IOrequests, windows, etc...). This takes care of Libraries and Devices. Other items EXEC would have to track would be those EXEC calls which transform the machine in some way... things intuitively obvious like SetIntVector(). The above is relatively simple and incurs almost no overhead in terms of memory and time, though it will mean an extensive rewrite of the OS. BUT now we come to memory. The problem with tracking memory is that in most cases programs allocate small chunks at a time and to stick a linked list (or some other structure) tag onto each chunk can, in the worst case, double the memory requirements of a task. Other problems occur when we are bandying messages back and forth between tasks... we must allow for multiple owners of a memory segment. Anybody have any bright ideas? COMPATIBILITY: It is impossible to make resource tracking compatible with current software. That is, you *can* resource track current software, but cannot free those resources when the task is killed even though you know what they are. REASON: Simply put, many programs rely on resources they haven't closed (memory, interrupts) NOT to be released when they exit. Another reason of equal import is the fact that under the current OS, you can RemTask() a task which is in the middle of a library call. Clearly, the libraries were not set up to handle something like that happenning!!!! Clearly we must add EXEC calls to allow resources to be kept resident on exit. Current software does not know about these calls so the ABSOLUTE BEST we can hope for is to make a standard for NEW software that is written. CONCLUSION: The end result would be that we would then be able to kill new programs which understand the new EXEC calls and still not be able to kill old programs which do not. New programs would make an EXEC call TrackResources() at the very beginning to turn on resource tracking and automatic deallocation, etc.... Since old programs do not make this call, EXEC knows they are old and will not attempt to track them. Under the new order, programs would be able to selectively turn on and off tracking for certain operations. Under the new system, Libraries and Devices would be constrained to set a flag (or something) ensuring they are not killed in the middle of execution when called from a task. If any task opens a library without this capability, resource tracking would automatically be turned off and kills would not be allowed on that task (Basically, you would not be able to kill any task which did not have resource tracking turned on). -Matt
jesup@steinmetz.steinmetz.UUCP (Randell Jesup) (09/09/87)
In article <636@sugar.UUCP> karl@sugar.UUCP (Karl Lehenbauer) writes: >If one were to do the same for RemTask, >one wouldn't need to explicitly call any special resource tracking code >at all! (Peter came up with this part. I think it'll work.) Sorry to disappoint you, but RemTask may not do you any good. Most Amiga programs return via rts; or Forbid()ing, ReplyMsg()ing, and then rts; or (EVIL!) Exit(). What you really need to do is what Lattice does, have cleanup code in the startup/exit module. -- Randell Jesup (Please use one of these paths for mail) jesup@steinmetz.UUCP (uunet!steinmetz!jesup) jesup@ge-crd.ARPA
bryce@hoser.berkeley.edu (Bryce Nesbitt) (09/09/87)
In article <> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes: > >COMPATIBILITY: > It is impossible to make resource tracking compatible with current >software... REASON: Simply put, many programs rely on resources they haven't >closed (memory, interrupts) NOT to be released when they exit. Good point. I have written several programs that deliberatly leave memory allocated after a sucessful exit. Read on... >Clearly we must add EXEC calls to allow resources to be kept resident >on exit. Current software does not know about these calls so the ABSOLUTE BEST >we can hope for is to make a standard for NEW software that is written. Um... Read on... >CONCLUSION: > The end result would be that we would then be able to kill new >programs which understand the new EXEC calls and still not be able to kill >old programs which do not. Argh!!! I think this is a _very_ wrong approach. You see, it says "Every last person who _ever_ writes _any_ software must know about this and use it. *All* of you, every one. And, you must do it correctly.". Chances of getting everybody to do this are so near zero as to be uncountable. Think of all the software now that uses busy waits, or MOVE SR,<ea> or any other forbidden fruit. If it's done like that, 5 years from now there will still be untrackable software that will force people to suffer from reboots, lost resources, whatever. A conversion of this magnitude is never easy... but there is a better way. There is a _much_ smaller base of programmers to target: People who write software that must leave resources. What you do is _well_ before the resource tracking goes in publish a tech note (to use an Apple-ism) explaining the situation. Explain that if you must leave a resource dangling *YOUR PROGRAM WILL BREAK WHEN OS VX.X IS RELEASED*. Then describe a check or work arround that will let your software work now and *AND* in the resource tracked future. Apple is a company that has done very well at doing the "impossible" upgrade. They even switched from the brain-dead "flat" MFS to a filesystem that actually knows about subdirectories! I talked with <name deleted>, a leading Mac software publisher. They had a software package in final Q&A. A tech note came from Apple warning about some future updates. They listened and delayed the shipping for one week. Nearly a year later Apple released a new system file. The thing that was supposed to change did... and because of the last moment change, the program still worked. I guess what I'm saying is that this is a tried and true tactic. The Intuition LockIBase() call seems like a good example. It was in V1.1 but was just a stub. In V1.2 jimm added some code to go with it. The ultimate in structured programming... not only was it documented before it was written, but people were using it! :-) :-) :-) > libraries and devices. Libraries and devices may need to help in the resource tracking. What can be done to let old ones run may become a problem. |\ /| . Ack! (NAK, EOT, SOH) {O o} . (") bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce U
dillon@CORY.BERKELEY.EDU (Matt Dillon) (09/09/87)
>>CONCLUSION: >> The end result would be that we would then be able to kill new >>programs which understand the new EXEC calls and still not be able to kill >>old programs which do not. > >Argh!!! I think this is a _very_ wrong approach. You see, it says "Every >last person who _ever_ writes _any_ software must know about this and >use it. *All* of you, every one. And, you must do it correctly.". >Chances of getting everybody to do this are so near zero as to be >uncountable. Think of all the software now that uses busy waits, >or MOVE SR,<ea> or any other forbidden fruit. >If it's done like that, 5 years from now there will still be untrackable >software that will force people to suffer from reboots, lost resources, >whatever. No, you simply have one call to EXEC 'TrackResource(TRUE)'. Presumably the major compilers (Manx/Lattice) would incorporate this into their assembly code. Commodore isn't stable enough (yet) to be able to release a new OS which makes half the software in existance incompatible. I have an idea: Make the resource tracking contingent on a new DOS. That is, if C-A releases a new DOS *everybody* will use it, and we can make the resource tracking 'forced' automatically upon any program using the new DOS (as well as have the EXEC calls mentioned above). Reason: Anybody who knows about the new DOS (Assuming C-A releases one) would also know about the automatic resource tracking and write their programs accordingly. Is that convoluted or What? -Matt
mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (09/10/87)
In article <8709091634.AA19588@cory.Berkeley.EDU> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
< I have an idea: Make the resource tracking contingent on a new DOS.
This appears to be the only solution. The problem is (as stated
before) that the Amiga probably can't survive a non-compatable (or at
least mostly non-compatable) upgrade at this point. Maybe a two-phase
upgrade, over the course of a year or more:
Phase 1) A new DOS that is backwards compatable, but supports resource
tracking if you want it. This should include notes on how to make a
program track resources, and warnings that the resource tracking will
be mandatory in the future.
Phase 2) The mandatory resource tracking version, that is *not*
backwards compatable.
The reason for this is that there are more nasties than you want to
think about with adding the ability to kill a task. For instance,
let's take a trivial example:
CLIENT opens port "server.port" and sends it a message containing some
text.
SERVER recieves the message from CLIENT, and goes away to do things
based on the text of the message.
Later, the SERVER is through with the text, so it does a ReplyMsg() on
the saved message.
CLIENT gets the reply, frees the port & etc, and then goes about it's
merry business.
Now, add resource tracking and the ability to kill a task/process to
this picture. Suddenly, CLIENT has to be able to deal with "He's dead,
Jim" messages on the reply port, and SERVER has to be able to figure
out which of the ports it's hanging onto should be thrown out when it
gets a "He's dead" message on "server.port".
Likewise for *any* resource that might be shared between two
processes. Especially if the protocol is such that task1 allocates the
resource, fills it and passes it to task2, who will free it.
Basically, you need a new set of mechanisms. One for indicating which
resources you do/don't want freed, whether it's shared or not (and
with who), and what you want done if one of the sharers dies. Plus, of
course, ways of indicating that you're picking up a shared resource,
and what to do etc.
Of course, I'd love to be wrong, and see a transparent way of doing
resource tracking including shared resource & death of shareholders
without breaking existing code. Anyone wanna try?
<mike
--
The handbrake penetrates your thigh. Mike Meyer
A tear of petrol is in your eye. mwm@berkeley.edu
Quick, let's make love before we die. ucbvax!mwm
On warm leatherette. mwm@ucbjade.BITNET
fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (09/11/87)
in article <636@sugar.UUCP#, karl@sugar.UUCP (Karl Lehenbauer) says:
# The question often comes up on the net, "How can I kill my Amiga tasks?" or
# more often, "Why can't I kill my Amiga tasks?". The problem, of course,
# is resource tracking, or more specifically the lack of support for it under
# AmigaDOS...
#
# We should do that, too. The memory allocation problem can be solved
# by using AllocRemember (Thanks, Peter, for showing me this).
# Library routines would front-end calls to create message ports and
# such. The library routines would keep track of what things need to
# be cleaned up on termination and how to do the cleanup in addition
# to making the system calls to perform the specified operations. The
# _main (for C people) startup code would set up to receive a software
# interrupt on the various control keys. The interrupt would call the
# code that cleans everything up.
#
As I understand it, that is exactly how Lattice handles the problem
with version 3.10 of their C compiler. I believe you have the option of
disabling that code, but the default is to trap BREAKs (^C) and put up a
requester asking if you wish to continue or abort. Doesn't that pretty
well solve the problem for Lattice users?
--Fabbian Dufoe
350 Ling-A-Mor Terrace South
St. Petersburg, Florida 33705
813-823-2350
UUCP: ...gatech!codas!usfvax2!jc3b21!fgd3
peter@sugar.UUCP (Peter da Silva) (09/12/87)
In article <8709082136.AA19121@cory.Berkeley.EDU>, dillon@CORY.BERKELEY.EDU (Matt Dillon) writes: > now we come to memory. The problem with tracking memory is that in most cases > programs allocate small chunks at a time and to stick a linked list (or some > other structure) tag onto each chunk can, in the worst case, double the > memory requirements of a task. Other problems occur when we are bandying > messages back and forth between tasks... we must allow for multiple owners > of a memory segment. Anybody have any bright ideas? Put up with doubling the memory requirements of the task, or else allocate a bigger chunk to each task (say: 128 bytes minimum), and give it bits of this chunk as it requires. Make AllocMem act more like Malloc. The free list within the 128 byte chunk can be manipulated as normal. Messages are tougher. If SendMsg transfers the ownership of the segment containing the message, or better yet marks it as having shared ownership, that should help most cases... shared chunks can't be freed automatically. It's still not perfect, but the only place this will cause problems is if you kill the task. All messages should be back at the originator by the time the task exits normally. Killing a task is an emergency measure anyway. > COMPATIBILITY: > It is impossible to make resource tracking compatible with current > software. That is, you *can* resource track current software, but cannot > free those resources when the task is killed even though you know what they > are. REASON: Simply put, many programs rely on resources they haven't > closed (memory, interrupts) NOT to be released when they exit. I don't think they should do this. The only resource a program should expect to hang around is a process it has LoadSegment()ed and CreateProcess()ed. And which has its own resources. Cna you name any programs that expect anything else to hang around after they go away? The only one I can think of is something that chews up RAM so your 512K-only programs can run. Oh yes, the Manx SET command, but that's a little joker that can easily be rewritten to give up its memory nicely. > Another > reason of equal import is the fact that under the current OS, you can > RemTask() a task which is in the middle of a library call. Clearly, the > libraries were not set up to handle something like that happenning!!!! This is a real problem. But since we're modifying the libraries anyway and not using RemTask to Kill tasks, it's no real bigee. > Clearly we must add EXEC calls to allow resources to be kept resident > on exit. Current software does not know about these calls so the ABSOLUTE BEST > we can hope for is to make a standard for NEW software that is written. I don't see why. One mark of a good program is that when you exit the Free Memory list in the workbench title bar hasn't changed. Most software should in fact work well with resource tracking. > CONCLUSION: > The end result would be that we would then be able to kill new > programs which understand the new EXEC calls and still not be able to kill > old programs which do not. We would also be able to kill old programs that were well-behaved. Also, this will have to be done eventually to allow for protected mode operation. Why not start now. Look how well burying heads in the sand has worked for IBM and Microsoft. If the Amiga doesn't go to protected mode it will be dead within 5 years. -- -- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter -- 'U` <-- Public domain wolf.
peter@sugar.UUCP (09/14/87)
> As I understand it, that is exactly how Lattice handles the problem > with version 3.10 of their C compiler. I believe you have the option of > disabling that code, but the default is to trap BREAKs (^C) and put up a > requester asking if you wish to continue or abort. Doesn't that pretty > well solve the problem for Lattice users? Lattice and Aztec both check the value of SIGB_CTRL[CDEF] when you call their runtime libraries. Programs that do not use standard I/O won't be helped by this, because SIGB_CTRL[CDEF] will never be checked. Anyway, when these signal bits are detected, Aztec just calls _abort and exits. Lattice puts up this requestor then calls its equivalent of _abort and exits. To get a SIGB_CTRL[CDEF], you have to be run from the CLI. Programs that run from the workbench won't be helped by this. Also, all this cleans up is the stdio stuff (files opened with fopen, memory allocated with malloc)... you have to write your own _abort routine to catch your windows and AllocMemmed memory (which you need some of in any case: you shouldn't be malloccing a FileInfoBlock, for example, or anything that needs to be in CHIP memory). With Lattice this may or may not be possible. Also, I'm a little doubtful of the value of popping up a requestor. What if you're running remotely? I know there are some requestors you can't avoid, but is it really such a good idea to add another? CLI-based programs should try their damndest to avoid needing the screen. -- -- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter -- 'U` ^^^^^^^^^^^^^^ Not seismo!soma (blush)
dpvc@ur-tut.UUCP (Davide P. Cervone) (09/15/87)
[RoboCop wasn't thuroughly debugged yet...] I have a concern that doesn't seem to have been addressed yet in the "kill any process" suggestions. While I beleive that there have been excellent methods proposed for making it possible to free up memory that's been allocated by a process, I'm not sure that that's all there is to it. One must look at how that memory is being used. For instance, if the memory is part of a message that has been sent to another process, and that process is still using that memory when you kill the original process, then you will be freeing memory that is in use (not a good idea). Does this mean that when we kill a process, we should Wait() for all outstanding messages to be replied to? But what if the messages are never returned (like there is still a bug in the program we're debugging)? Do we not remove the process? Or do we remove it anyway, and possibly risk a crash later? How about other process that have pointers into the memory that I am using. Suppose for instance, that I call OpenWindow() to get a new winodw. That allocates memory. It also links my window into the screen's window list, creates a Layer structure and links that into the screen's LayerInfo structure. If I deallocate that memory without properly closing the window, the screen's window and LayerInfo lists will point to invalid data. This could cause serious problems when I start to do aything with windows (like refresh them). How about if a fopen() a CON: window? That causes a new console task to be born (this takes up memory, but it belongs to another task). If someone kills my process without closing that CON: window, the console process will never be removed, and will stick around in memory, doing I-don't-know-what. Similarly, if I open the serial port, but don't close it properly (even if I free the memory I used), no one else will be able to access the serial port. While it is possible to encapsulate all the DOS and exec routines that allocate memory or other resources within new routines that track them, I am not so sure it's a practical thing to add in after the fact. There may just be too many to change. I hope I'm wrong, but it's not a project to be taken lightly. And you need to realize that just freeing memory isn't enough (and sometimes it's too much, like when that memory is in use by another process). In an environment where process share their resources in so many ways, I really worry about cleaning up after a process without some knowledge of what that process was doing. I hope someone finds a way to do it, though. Sorry for the length of this, but I hope it helps some people think about these issues. Davide P. Cervone dpvc@tut.cc.rochester.EDU dpvc@ur-tut.UUCP DPVC@UORDBV.BITNET
brianr@tekig4.UUCP (09/17/87)
This naive suggestion is only just barely making it past my foot-in-mouth-avoidance inhibitions, so I'll keep it short: Is there any merit in the notion of maintaining a linked list of pointers to subroutines which do "cleanup" type activities such as device/window/message port closing, as well as memory deallocation? Sort of an extension to the Memlist idea. "Killing" a task would then involve scanning its "cleanup" list in reverse order of creation. The cleanup list is built by substitutes for the normal CreateXXXX functions; the substitutes call their forebears, and then add the appropriate information to the task's current cleanup list. The cleanup vector in some (maybe most) cases will be implicit (e.g., NewOpenWindow automatically links a pointer to a CloseWindow call), but some might have to be supplied explicitly. I suppose the list would have to be more than mere pointers to existing subroutines; it needs to include the appropriate parameters for those subroutines; probably faked-up stack frame images. This could tie up a fair ammount of memory in its own right, but would save a lot of code that's currently being generated in each of a zillion applications. The list-unwinding program would be included in the code currently pointed to by a Task's exit vector (I haven't my manuals handy, but I remember there being one). I haven't figured out how to deal with unreturned messages in this scheme, but there might be a way, mightn't there? Staring wistfully in through real programmers' windows, Brian Rhodefer