May 17, 2012
So that's the thing: You really need to know what the thread is doing or you should not be killing it. Predicting GC allocations is hard, but taking the global thread lock inside kill() eliminates that problem (at least I *think* it does; it covers any case that I can think of). In most cases where you kill threads, you either know what they are doing, or assume that *they* know what they're doing (and that "what" being something that won't make the planet implode once they're killed).

Regards,
Alex

On Thu, May 17, 2012 at 12:59 AM, Sean Kelly <sean@invisibleduck.org> wrote:
> That forces the GC to expose functionality for acquiring any relevant locks for something that really has nothing to do with memory allocation., and still only takes care of one potential deadlock, albeit a common one.  Critical sections would help as well (that's basically how pthread_cancel() works), but applying them to this case would be tricky.
>
> On May 16, 2012, at 3:54 PM, Alex Rønne Petersen wrote:
>
>> Again, this boils down to knowing what you're doing. You should NOT be killing a thread if there is any chance whatsoever that the thread could be doing GC allocation while you do it.
>>
>> That said, I'm not convinced that this is a problem that we cannot work around; I think that if kill() would acquire the global thread lock, this problem could be prevented from happening.
>>
>> Regards,
>> Alex
>>
>> On Thu, May 17, 2012 at 12:52 AM, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>>> On Wednesday, May 16, 2012 14:44:12 Sean Kelly wrote:
>>>> If the killed thread even has a chance of allocating memory ir could be killed while inside the GC and lock all threads out of the GC forever.
>>>
>>> Ouch.
>>>
>>> - Jonathan M Davis
>>> _______________________________________________
>>> D-runtime mailing list
>>> D-runtime@puremagic.com
>>> http://lists.puremagic.com/mailman/listinfo/d-runtime
>> _______________________________________________
>> D-runtime mailing list
>> D-runtime@puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/d-runtime
>
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 16, 2012
On May 16, 2012, at 3:57 PM, Alex Rønne Petersen wrote:

> On Thu, May 17, 2012 at 12:28 AM, Sean Kelly <sean@invisibleduck.org> wrote:
>> On May 16, 2012, at 2:51 PM, Alex Rønne Petersen wrote:
>> 
>>> It's the user's responsibility, just as with any of the other 'unsafe' functions. Also, it's the runtime, not the standard library. I think there is a significant difference between those two terms. You shouldn't touch the runtime in general unless you're prepared to go low-level.
>> 
>> 
>> I think that there are three important aspects of library design.  The first is to make it useful by exposing any functionality that is commonly needed by users of the library, or in some cases that is not commonly needed but which can't be done without library support.  The second is that this should be done with the understanding that the interface of a library provides a framework for how the library is to be used.  This is the really tricky part, because a library could expose the same functionality in two different ways and the applications built upon each would be fundamentally different.  The third is that the library should be no more complex than absolutely necessary.  Doing so tends to expose too many assumptions about how the library will be used, and tends to confuse things without really adding much of use.
> 
> The problem is that druntime's core.thread is supposed to hide the native threading mechanism being used. With the example in your other email, the abstraction is completely broken, and portability becomes a *giant* pain (especially because compilers don't set any flags indicating what threading library the runtime is built for). So, I do believe kill() would be an important primitive to have, as unsafe as it is.

Fair enough.  I'm still resistant to Thread.kill() however, both because of how unsafe it is and because this is actually the first time anyone has ever requested it.


>> What I've found is that when people thing of something useful for their program, if it's something regarding a library they tend to want to build that functionality into the library even if it doesn't need to be there.  The problem is that they may be the only person in the world that needs that functionality, and adding it to the library may increase maintenance cost to no one's actual benefit but that one user.  There have been a number of requests like this for Druntime, and some of the few that were accepted have just been deleted after having been deprecated for years, without a single complaint.  Assuming that people are actually using Druntime, I'll admit that I prefer to see it shrinking rather than growing.  It means that it's being distilled down to only containing the functionality that people actually care about.
> 
> What were some of those (out of curiosity)?

Runtime.isHalting, for one.  There were others I didn't implement for one reason or another, like the ability to join a thread with a timeout.


> I agree that keeping druntime small is a good idea - but IMO that shouldn't mean that we can't have the abstractions that actually make druntime useful. Obviously, I'm biased here, since this is a feature I, specifically, want. But I'm not convinced that it would never be used by anyone else. D is a systems language intended to be a competitor to C and C++. A virtual machine is just one example of a system that would need the functionality to destructively kill threads, regardless of whether all hell breaks loose as a result.

Suspending threads is actually similar, since debuggers do have a valid reason to suspend threads.  I suppose I'm just leery of exposing any functionality that could cause a deadlock.
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 17, 2012
Trust me, I've evaluated every option I could think of. Even cooperative suspension/killing won't cut it because a while (true); inside a VM thread could prevent the cooperative kill from actually happening at all.

E.g.:

void myThread()
{
    while (run)
    {
        runUserCode(); // if this never returns, the thread will never stop
    }
}

Regards,
Alex

On Thu, May 17, 2012 at 12:55 AM, Sean Kelly <sean@invisibleduck.org> wrote:
> On May 16, 2012, at 3:42 PM, Alex Rønne Petersen wrote:
>
>> The trouble is that they have to have version blocks for every platform and every threading library supported. The fact that core.thread supports pthreads should not even be known to code that extends the Thread class; it's an implementation detail (other threading libraries exist, especially on Linux). I believe there is currently active work to make GDC support other C libraries, and I imagine that involves other threading libraries on rather exotic platforms too.
>>
>> The way I've always seen core.thread is as a fundamental building block for threading; it should hide the native threading interface completely so people shouldn't have to mess with those at all.
>
> I tend to agree, though for some of the really risky stuff I think it may be fair to expect the user to be familiar with the platform specifics of what he's trying to do.  Kill threads, for example, works differently on Posix vs. Win32 and is (surprise surprise) actually a bit safer.  Regarding killing threads in general though, I wonder if there isn't perhaps a safer application-specific approach that you could use.  Could these threads periodically check some global "cancel" state and exit if set?  Is it truly necessary to have an external thread violently kill them?
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 16, 2012
On May 16, 2012, at 4:06 PM, Alex Rønne Petersen wrote:

> Trust me, I've evaluated every option I could think of. Even cooperative suspension/killing won't cut it because a while (true); inside a VM thread could prevent the cooperative kill from actually happening at all.
> 
> E.g.:
> 
> void myThread()
> {
>    while (run)
>    {
>        runUserCode(); // if this never returns, the thread will never stop
>    }
> }

Maybe a standalone function like:

extern (C) int thread_terminateThread(Thread t);

That would at least keep it out of the public interface for the object, and move it into the realm of really unsafe or weird stuff.  Obvious caveat still being that the app may well have been left in an invalid state.
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 17, 2012
I agree. I'll have a go at implementing it and we can see where that goes.

Regards,
Alex

On Thu, May 17, 2012 at 1:22 AM, Sean Kelly <sean@invisibleduck.org> wrote:
> On May 16, 2012, at 4:06 PM, Alex Rønne Petersen wrote:
>
>> Trust me, I've evaluated every option I could think of. Even cooperative suspension/killing won't cut it because a while (true); inside a VM thread could prevent the cooperative kill from actually happening at all.
>>
>> E.g.:
>>
>> void myThread()
>> {
>>    while (run)
>>    {
>>        runUserCode(); // if this never returns, the thread will never stop
>>    }
>> }
>
> Maybe a standalone function like:
>
> extern (C) int thread_terminateThread(Thread t);
>
> That would at least keep it out of the public interface for the object, and move it into the realm of really unsafe or weird stuff.  Obvious caveat still being that the app may well have been left in an invalid state.
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 16, 2012
If you have code like this, how can you make the claims you have about knowing it to be safe to kill the threads in question.  I'm with Sean on this, killing threads is a really bad idea and having an api is going to result in pain.

The only safe way to do it is akin to what you describe above.  Rely on some communication path into the other thread to ask it to kill itself when it's actually safe, not just believed to be.

It's a lot like so called lockless programming.  It's _really_ hard to get right.  Even the experts get it wrong fairly frequently.  When you can avoid it, avoid it.  There are safe ways of asking a thread to exit itself, so that should be the much preferred method.

You're obviously a bright guy and know all this, so what's pushing you so hard to go in an obviously unsafe direction rather than the obviously safe one?

On Thu, 17 May 2012, Alex R?nne Petersen wrote:

> Trust me, I've evaluated every option I could think of. Even cooperative suspension/killing won't cut it because a while (true); inside a VM thread could prevent the cooperative kill from actually happening at all.
> 
> E.g.:
> 
> void myThread()
> {
>     while (run)
>     {
>         runUserCode(); // if this never returns, the thread will never stop
>     }
> }
> 
> Regards,
> Alex
> 
> On Thu, May 17, 2012 at 12:55 AM, Sean Kelly <sean@invisibleduck.org> wrote:
> > On May 16, 2012, at 3:42 PM, Alex R?nne Petersen wrote:
> >
> >> The trouble is that they have to have version blocks for every platform and every threading library supported. The fact that core.thread supports pthreads should not even be known to code that extends the Thread class; it's an implementation detail (other threading libraries exist, especially on Linux). I believe there is currently active work to make GDC support other C libraries, and I imagine that involves other threading libraries on rather exotic platforms too.
> >>
> >> The way I've always seen core.thread is as a fundamental building block for threading; it should hide the native threading interface completely so people shouldn't have to mess with those at all.
> >
> > I tend to agree, though for some of the really risky stuff I think it may be fair to expect the user to be familiar with the platform specifics of what he's trying to do.  Kill threads, for example, works differently on Posix vs. Win32 and is (surprise surprise) actually a bit safer.  Regarding killing threads in general though, I wonder if there isn't perhaps a safer application-specific approach that you could use.  Could these threads periodically check some global "cancel" state and exit if set?  Is it truly necessary to have an external thread violently kill them?
> > _______________________________________________
> > D-runtime mailing list
> > D-runtime@puremagic.com
> > http://lists.puremagic.com/mailman/listinfo/d-runtime
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
> 

May 17, 2012
On Thu, May 17, 2012 at 1:51 AM, Brad Roberts <braddr@puremagic.com> wrote:
> If you have code like this, how can you make the claims you have about knowing it to be safe to kill the threads in question.  I'm with Sean on this, killing threads is a really bad idea and having an api is going to result in pain.

I can because I know what the threads are doing. I'm doing this in a virtual machine; I know the threads are executing isolated, managed code. Heck, if I wanted, I could map their native instruction pointer back into my IR to see exactly what operation they were performing.

The important point, however, is that the threads in question can only mutate state that I know everything about, and I'm doing this daemon thread killing on shutdown. That means that the managed system is left in a very fragile state, but it doesn't matter, because the world has completely stopped at that point (all managed, non-daemon threads have been joined before killing the daemon threads). This is what I mean when I say you have to reason about *exactly* what the thread you're killing is doing, or you shouldn't be killing it at all.

The cases where you can actually kinda-sorta safely kill a thread are so extremely rare, but they do exist.

>
> The only safe way to do it is akin to what you describe above.  Rely on some communication path into the other thread to ask it to kill itself when it's actually safe, not just believed to be.

The thing is, that's not so useful in practice: Every programmer working with my VM would have to make their daemon threads cooperatively check for a shutdown condition frequently. And while this is arguably a much better programming model than what people do today, I can't reasonably force it upon people (it would also render my VM incompatible with the majority of existing programming languages in the threading department). Besides, cooperative killing means that the thread may not be killed at all if the managed code so desires; I can't afford that. I need to be able to guarantee that the VM shuts down (well, almost; most thread killing APIs don't actually guarantee all that much, but in practice, they tend to work).

>
> It's a lot like so called lockless programming.  It's _really_ hard to get right.  Even the experts get it wrong fairly frequently.  When you can avoid it, avoid it.  There are safe ways of asking a thread to exit itself, so that should be the much preferred method.

I really would if I could! But this is a virtual machine, so asking the thread at some arbitrary point to just shut itself down is not practical. I know that the thread is executing managed code, but I don't know *what* that code means; that's entirely up to the programmer of the application the VM is executing. But as far as VM shutdown is concerned, what the code does is irrelevant, since I'm abandoning the managed world completely on shutdown anyway (in practice, this equals zeroing all of the managed application's globals, unregistering all roots, doing a GC cycle, and waiting for finalizers to complete (the last one is another can of worms entirely...)).

>
> You're obviously a bright guy and know all this, so what's pushing you so hard to go in an obviously unsafe direction rather than the obviously safe one?

See above. I believe in my specific case, I have enough control to make this 'safe enough'.

>
> On Thu, 17 May 2012, Alex R?nne Petersen wrote:
>
>> Trust me, I've evaluated every option I could think of. Even cooperative suspension/killing won't cut it because a while (true); inside a VM thread could prevent the cooperative kill from actually happening at all.
>>
>> E.g.:
>>
>> void myThread()
>> {
>>     while (run)
>>     {
>>         runUserCode(); // if this never returns, the thread will never stop
>>     }
>> }
>>
>> Regards,
>> Alex
>>
>> On Thu, May 17, 2012 at 12:55 AM, Sean Kelly <sean@invisibleduck.org> wrote:
>> > On May 16, 2012, at 3:42 PM, Alex R?nne Petersen wrote:
>> >
>> >> The trouble is that they have to have version blocks for every platform and every threading library supported. The fact that core.thread supports pthreads should not even be known to code that extends the Thread class; it's an implementation detail (other threading libraries exist, especially on Linux). I believe there is currently active work to make GDC support other C libraries, and I imagine that involves other threading libraries on rather exotic platforms too.
>> >>
>> >> The way I've always seen core.thread is as a fundamental building block for threading; it should hide the native threading interface completely so people shouldn't have to mess with those at all.
>> >
>> > I tend to agree, though for some of the really risky stuff I think it may be fair to expect the user to be familiar with the platform specifics of what he's trying to do.  Kill threads, for example, works differently on Posix vs. Win32 and is (surprise surprise) actually a bit safer.  Regarding killing threads in general though, I wonder if there isn't perhaps a safer application-specific approach that you could use.  Could these threads periodically check some global "cancel" state and exit if set?  Is it truly necessary to have an external thread violently kill them?
>> > _______________________________________________
>> > D-runtime mailing list
>> > D-runtime@puremagic.com
>> > http://lists.puremagic.com/mailman/listinfo/d-runtime
>> _______________________________________________
>> D-runtime mailing list
>> D-runtime@puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/d-runtime
>>
>
> _______________________________________________
> D-runtime mailing list
> D-runtime@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime
>

Regards,
Alex
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 17, 2012
One interesting question in designing a kill function is: Do we want to guarantee that it runs all the thread shutdown routines (see the shutdown code in thread_entryPoint)? I'm thinking that guaranteeing this is basically impossible, so I'm leaning towards no. The most I can see would be realistic is to remove the thread from the global thread list if enqueueing the termination request (pthread_cancel on POSIX, TerminateThread on Windows) succeeded.

If we don't guarantee this, how much resource leakage are we looking at?

Regards,
Alex

On Wed, May 16, 2012 at 7:04 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> Hi,
>
> In my virtual machine, I need to be able to kill daemon threads on shutdown. The problem is that VM shutdown is *not* tightly coupled to druntime shutdown; multiple VM instances can run in a process at any given time, and can be started/stopped whenever. It doesn't appear like there is any functionality in core.thread to achieve this.
>
> Is there any reason we don't have a Thread.kill() function?
>
> Regards,
> Alex
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 17, 2012
Actually removing the thread from the global thread list would be bad, since the pthread cleanup callback will most likely access it. So, I see two ways to solve this:

a) Once the thread has been scheduled for termination, join it
immediately and pray that everything goes well, and then remove it
from the global list. This won't work if the code inside the thread
has altered its cancelability state with
pthread_setcancel[state,type], but I don't think this is worth
worrying about. If someone uses those functions and tries to kill the
thread, they probably know what they are doing and are prepared for
the consequences of calling the kill function with a thread in a
non-cancelable state (it's actually not necessarily problematic as
long as they obey the cancellation request inside the thread -
obviously, it's threading library-specific, though).
b) Enqueue the termination request, and just return immediately. This
means that the thread won't be removed from the global thread list
until something (i.e. thread_suspendAll) notices that it's dead
(!t.isRunning). While this is the easiest solution, I don't think it's
very clever; normally, you'd expect the thread to have terminated by
the time the kill function returns.

Personally, I'm in favor of (a).

The problem with guarantees about thread cleanup still stands, though.

Regards,
Alex

On Thu, May 17, 2012 at 2:55 AM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
> One interesting question in designing a kill function is: Do we want to guarantee that it runs all the thread shutdown routines (see the shutdown code in thread_entryPoint)? I'm thinking that guaranteeing this is basically impossible, so I'm leaning towards no. The most I can see would be realistic is to remove the thread from the global thread list if enqueueing the termination request (pthread_cancel on POSIX, TerminateThread on Windows) succeeded.
>
> If we don't guarantee this, how much resource leakage are we looking at?
>
> Regards,
> Alex
>
> On Wed, May 16, 2012 at 7:04 PM, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:
>> Hi,
>>
>> In my virtual machine, I need to be able to kill daemon threads on shutdown. The problem is that VM shutdown is *not* tightly coupled to druntime shutdown; multiple VM instances can run in a process at any given time, and can be started/stopped whenever. It doesn't appear like there is any functionality in core.thread to achieve this.
>>
>> Is there any reason we don't have a Thread.kill() function?
>>
>> Regards,
>> Alex
_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime

May 17, 2012
Le 2012-05-16 à 19:22, Sean Kelly a écrit :

> Maybe a standalone function like:
> 
> extern (C) int thread_terminateThread(Thread t);
> 
> That would at least keep it out of the public interface for the object, and move it into the realm of really unsafe or weird stuff.  Obvious caveat still being that the app may well have been left in an invalid state.

int thread_terminateThread(string disclaimer)(Thread t) if (disclaimer == "I know it will leak and could deadlock once in a while. I have read the documentation and accepts the consequences.");

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

_______________________________________________
D-runtime mailing list
D-runtime@puremagic.com
http://lists.puremagic.com/mailman/listinfo/d-runtime