erich@kgw2.bwi.WEC.COM (Eric Hammond) (02/20/90)
In article <1126@mtxinu.UUCP> frk@mtxinu.UUCP (Frank Korzeniewski) writes: > Fine, but what about other ports that the thread had recieve rights for. > Don't these ports give the rights back to the owner/backup thread? > If not, this seems to be a lack of appropriate cleanup by cthreads/mach. [...] > Again, special caseing the kernel port is ok, *IF* you correctly clean > up other ports that have been created. Leaving around these other > ports would seem to eventually result in resource exhaustion. In my response to this I am not flaming or putting down Frank. There just seems to be a common misconception about port rights and I would like to try to clear things up a bit for Mach programmers. I wish this had been explicitly pointed out to me when I first started multi-thread programming on the NeXT. From the Mach documentation from CMU (9 Jan 90): "Acess rights to a port consist of the ability to send to, receive from, or own that port. A task may hold just send rights or any combination of receive and ownership rights plus send rights. Threads within a task may only refer to ports to which that task has been given access. When a new port is created within a task, that task is given all three access rights to that port." "Every task has its own port name space, used for port and port set names." Mach port rights are owned by a task not a thread. All threads in a task have equal rights to all ports. (none, send, receive, ownership/backup). All threads in a task also have the same name for any given port that the task has rights to. When a thread creates a new port all threads in that task have all rights to that port. However, not all threads in that task may know the name of that port unless the creating thread communicates that name to the other threads (via global memory). If the creating thread dies, the task (and all threads in it) still have rights to that port. As Frank points out above, this could indeed result in resource exhaustion if the programmer does not take care. [ Killing a thread that the cthread library thinks it is using may be bad. ] > Other than efficiency, I see no justification for this statement. As > long as the os cleans up appropriatly, there should be no problem. > After all, that is what an os is for. (:-) I don't know the implementation of the cthreads library (which, by the way, may vary from machine/os/compiler to same), but I'd like to try to offer some justification for this statement. When you do a call to thread_terminate() you are terminating the actual low level thread that the Mach kernel knows about. This also will deallocate that thread's kernel port (among other things). The Mach kernel knows nothing about what we refer to as "cthreads". The cthread library is a user level run-time library used to interface with the low-level thread primitives. The cthread library associates several items with a Mach thread. One of these is an arbitrary pointer (cthread_set/get_data()). Another is a string name (cthread_set_name()). In my implementation on the NeXT all this information is stored in a structure (see cthreads.h). The type cthread_t is a pointer to this structure. Whenever a program makes a call on behalf of a cthread this pointer is passed to the library routine. The library routine can use any of the entries in the structure, the most important one being the name of the actual Mach thread. This is really the name of the kernel port of the Mach thread. If a program calls thread_terminate(cthread_thread(cthread_name)), this performs a kernel function which terminates the Mach thread, and deallocates the kernel port of the Mach thread. However, the cthread library knows nothing about this transaction; it still has a structure filled with information including the (no longer valid) name of a port. Since we don't know the implementation of the cthreads library it is best not to make assumptions. We should not, therefore, assume that the cthreads library will reference this port name in the future. This could cause possibly serious effects as that port name may be reused by the Mach kernel for another port (even another thread's kernel port). It might also be helpful to note that we shouldn't just deallocate the cthread structure by ourselves. We don't know what other references the cthreads library may have to that structure. (In my implementation it is part of a linked list.) (my) conclusion: Don't kill a thread out from under the cthreads library until we hear from a true Mach expert (someone with authority who can state that cthread implementations are and will be written to handle this). > Please don't say that it is bad form to just exit on an error. > It can be very difficult for an application to track all system > resources that are being used, and then free them at termination > to avoid possible later deadlock or other failures. Sending > your own notification is just one example of this. I agree with you, Frank. It is difficult to track all resources that a thread uses and might have to free up at termination. However, it is necessary if the thread ever plans on terminating (on error condition or otherwise) while other threads live on. Most resources are automatically freed upon task termination, and this is what we have been used to in Un*x. (The problem may be that we are using threads in a situation where multiple tasks are called for.) From the Mach documentation from CMU (9 Jan 90): "A task is an execution environment and is the basic unit of resource allocation." "A thread is the basic unit of execution. It consists of all processor state (e.g. hardware registers) necessary for independent execution. A thread executes in the virtual memory and port rights context of a single task." "Tasks contain the capabilities, namely the port rights, resource limits, and address space of a running entity. Tasks perform no computation; they are a framework for running threads." "Threads contain the minimal processing state associated with a computation, e.g. a program counter, a stack pointer, and a set of registers." (my) conclusion: If you are allocating ports, memory, or other resources like this, you should keep track of them. Again, this is probably only necessary if your thread might terminate while other threads continue, and is especially necessary if these types of threads are repeatedly created in your task. -- Eric Hammond erich@kgw2.bwi.wec.com