How to kill an overlapped thread ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

How to kill an overlapped thread ?

maurel
 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 ?


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Schwab,Wilhelm K
> 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]


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Bernhard Kohlhaas-7
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


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Chris Uppal-3
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


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Blair McGlashan-3
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


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Bernhard Kohlhaas-6
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


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Blair McGlashan-3
"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.


Reply | Threaded
Open this post in threaded view
|

Re: How to kill an overlapped thread ?

Bernhard Kohlhaas-7
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