From Dolphin I am calling an external dll, I am using the overlap
mechanism because the call returns in 10 mins. Is there a way to stop such a call while it is executing ? perhaps by killing the overlapped thread ? I read in the Dolphin Education center that the threads used to perform overlapped calls are maintained in a pool. How can I get a reference to that pool ? |
> From Dolphin I am calling an external dll, I am using the overlap
> mechanism > because the call returns in 10 mins. > > Is there a way to stop such a call while it is executing ? perhaps by > killing > the overlapped thread ? Dolphin tries to avoid being overly aggressive about terminating the OS thread, which is wise. I had a less severe but similar problem, and (IIRC) Blair was going to add some type of panic option that would simply terminate the OS thread. It seems that anything that takes 10 minutes to run should at least check with an OS event or otherwise allow one to induce a graceful exit. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by maurel
maurel wrote:
> From Dolphin I am calling an external dll, I am using the overlap > mechanism > because the call returns in 10 mins. > > Is there a way to stop such a call while it is executing ? perhaps by > killing > the overlapped thread ? I haven't found one, even Process>>kill doesn't terminate the OS thread in my case, an overlapped call to WinAPI function ReadDirectoryChangesW. Since this function monitors certain events in the file system, i.e. a file was created, I am creating such an event myself by creating a temporary file (and subsequently deleting it). This way the API call returns and the forked Smalltalk process can detect the termination condition and end itself. It's not pretty and it has some drawbacks, i.e. if the user doesn't have write-permission, but it's currently the only solution I found for this problem. Perhaps something similar might work in your case. > I read in the Dolphin Education center that the threads used to perform > overlapped calls are maintained in a pool. > How can I get a reference to that pool ? I doubt that this would be appropriate, since the Smalltalk process that initiated the overlapped call would be in an undefined state, if the OS thread was killed. What I'd like to see is, that terminating or killing a Smalltalk process would automatically and immediately kill all overlapped OS threads. I don't know though who's to blame in my case, Dolphin or Windows itself. Best Regards, Bernhard |
In reply to this post by maurel
maurel wrote:
> From Dolphin I am calling an external dll, I am using the overlap > mechanism > because the call returns in 10 mins. > > Is there a way to stop such a call while it is executing ? perhaps by > killing > the overlapped thread ? I don't think it's ever a good idea to kill executing code (in any language) without the co-operation of that code. E.g. if you kill a thread running code in an external DLL then you could cause all kinds of damage to that code's datastructures (trash the malloc arena, for instance). But if you /do/ have the co-operation of the other code (e.g. you wrote it yourself) then it becomes easy to set a "stop" flag that the code checks periodically. If not then I'd say that the only safe (in general) thing to do is to start a new OS process to do the work (start a .exe). That should be safe to kill, provided that it's been properly written. Alternatively, you could just let the operation run to completion and ignore the result (simple, but not such a great idea if the external function is compute-heavy or is doing a lot of I/O). -- chris |
In reply to this post by Schwab,Wilhelm K
"Bill Schwab" <[hidden email]> wrote in message
news:cvkkgb$12ue$[hidden email]... >> From Dolphin I am calling an external dll, I am using the overlap >> mechanism >> because the call returns in 10 mins. >> >> Is there a way to stop such a call while it is executing ? perhaps by >> killing >> the overlapped thread ? > > Dolphin tries to avoid being overly aggressive about terminating the OS > thread, which is wise. I had a less severe but similar problem, and > (IIRC) Blair was going to add some type of panic option that would simply > terminate the OS thread. > > It seems that anything that takes 10 minutes to run should at least check > with an OS event or otherwise allow one to induce a graceful exit. Long running calls that enter alertable wait states (see MSDN for more info on what this is) will be terminated gracefully. This is because Dolphin terminates the overlapped threads by sending then an Asynchronous Procedure Call (APC - see MSDN again) to raise an exception in them, rather than by calling TerminateThread(). In general its not safe to call TerminateThread(), here are some choice quotes from the reference page on MSDN: "...the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating." "TerminateThread is a dangerous function that should only be used in the most extreme cases.You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems: a.. If the target thread owns a critical section, the critical section will not be released. b.. If the target thread is allocating memory from the heap, the heap lock will not be released. c.. If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. d.. If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL." You might well get away with calling TerminateThread sometimes, or even most of the time, but its impossible to be certain that it hasn't caused some resource to remain locked or otherwise in use. By raising an exception Dolphin is giving well written code an opportunity to clean up, but again this can only be done when the thread has entered a "safe" state, such as an alertable wait state. It does this if it calls various process synchronisation primitives indicating that it is safe for it to be alerted. Consider the example of the process heap, should you be luck enough to terminate a thread while it is allocating memory from the process heap then (a) it might be corrupted, (b) it could be left locked. Either way your application process' life is over. Normally there is a clean way to terminate long running API calls. I notice that in this particular case you are calling ReadDirectoryChangesW. I think that if you simply close the directory handle that you are monitoring with it (i.e. call KernelLibrary>>closeHandle:), then the overlapped ReadDirectoryChangesW will immediately abort. Regards Blair |
Blair,
Thank you very much for this very detailed explanation. One comment I'd like to make: [...] > Normally there is a clean way to terminate long running API calls. I notice > that in this particular case you are calling ReadDirectoryChangesW. I think > that if you simply close the directory handle that you are monitoring with > it (i.e. call KernelLibrary>>closeHandle:), then the overlapped > ReadDirectoryChangesW will immediately abort. Since /I/ am the one who is using ReadDirectoryChangesW (rather than the original poster), I have to tell you that your suggestion unfortunately does /not/ work. :( When I try to close the handle with the call to ReadDirectoryChangesW still blocking, the execution of closeHandle will block. Once I unblock the ReadDirectoryChangesW by creating my own file action in that directory, the directory handle can be closed. That was my motivation to have that thread killed in the first place, so that I would (hopefully) be able to close the directory handle. Best Regards, Bernhard |
"Bernhard Kohlhaas" <[hidden email]> wrote in
message news:[hidden email]... > Blair, > > Thank you very much for this very detailed explanation. One comment I'd > like to make: > > [...] > > >> Normally there is a clean way to terminate long running API calls. I >> notice that in this particular case you are calling >> ReadDirectoryChangesW. I think that if you simply close the directory >> handle that you are monitoring with it (i.e. call >> KernelLibrary>>closeHandle:), then the overlapped ReadDirectoryChangesW >> will immediately abort. > > Since /I/ am the one who is using ReadDirectoryChangesW (rather than the > original poster), I have to tell you that your suggestion unfortunately > does /not/ work. :( > And I have to tell you that it does. At least if does if you include the FILE_FLAG_OVERLAPPED flag when opening the directory handle, otherwise attempting to close it will indeed block. > When I try to close the handle with the call to ReadDirectoryChangesW > still blocking, the execution of closeHandle will block. Once I unblock > the ReadDirectoryChangesW by creating my own file action in that > directory, the directory handle can be closed. > > That was my motivation to have that thread killed in the first place, so > that I would (hopefully) be able to close the directory handle. As MSDN makes very clear, calling TerminateThread is a bad idea in a process that you wish to keep running. Regards Blair -------------------------- handle := KernelLibrary default createFile: 'c:\' dwDesiredAccess: 1"FILE_LIST_DIRECTORY" dwSharedMode: 3 "FILE_SHARE_READ | FILE_SHARE_WRITE" lpSecurityAttributes: nil dwCreationDistribution: 3 "OPEN_EXISTING" dwFlagsAndAttributes: "33554432" 1107296256 "FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED" hTemplateFile: nil. buffer := ByteArray newFixed: 8192. count := DWORD new. p := [KernelLibrary default readDirectoryChangesW: handle lpBuffer: buffer nBufferLength: buffer size bWatchSubtree: false dwNotifyFilter: 19 "(FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME)" lpBytesReturned: count lpOverlapped: nil lpCompletionRoutine: nil. Sound beep] fork KernelLibrary default closeHandle: handle. |
Blair McGlashan wrote:
> > And I have to tell you that it does. At least if does if you include the > FILE_FLAG_OVERLAPPED flag when opening the directory handle, otherwise > attempting to close it will indeed block. Hi Blair, You are right of course, I didn't use the FILE_FLAG_OVERLAPPED flag. Thank you for trying this. :) I noticed two other things: - When you close the file handle, while the call to ReadDirectoryChangesW is "unblocked", so the Smalltalk process can end in a graceful way. That comes in very handy. - A strange thing is that, when a file event actually happens and the forked process ends, before closing the handle an twofold evaluation of "KernelLibrary default closeHandle: handle" will answer "true" the 2nd time as well (at least if the 2nd eveluation is within a few seconds of the 1st). Perhaps just another Windows oddity. > As MSDN makes very clear, calling TerminateThread is a bad idea in a process > that you wish to keep running. And since now the thread is unblocked when closing the handle, there is no need to kill it in the first place. Best Regards, Bernhard |
Free forum by Nabble | Edit this page |