Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re^11: The implementation of SIGHUP in Win32 Perl (non-synchronous IO )

by BrowserUk (Patriarch)
on Sep 11, 2013 at 23:25 UTC ( [id://1053604]=note: print w/replies, xml ) Need Help??


in reply to Re^10: The implementation of SIGHUP in Win32 Perl (non-synchronous IO )
in thread The implementation of SIGHUP in Win32 Perl

But that is in C, the Anon I assume, and I was referring to XS

Sorry, but I fail to see the distinction between "C" and "XS". They are one and the same.

Would I even attempt it via Win32::API, and 'pure perl' (that's ironic) -- given the history of failures with Win32::API and callbacks, even before you introduce the idea of those callbacks be invoked by the system at some random point in the future possibly on a completely different thread -- no.

Before you try and shoot me down in flames; read the entirety (all 26 levels) of Perl crash during perl_clone so that you understand that I understand the requirements and problems of asynchronous, cross-thread callbacks very, very well.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
  • Comment on Re^11: The implementation of SIGHUP in Win32 Perl (non-synchronous IO )

Replies are listed 'Best First'.
Re^12: The implementation of SIGHUP in Win32 Perl (non-synchronous IO )
by bulk88 (Priest) on Sep 12, 2013 at 00:33 UTC
    Kernel32 I/O will never create threads. APCs dont do it. IO Completion Ports don't do it, and doing a WaitForMultipleObjects won't create threads.

    Perl crash during perl_clone, I would have done it a different way than was done in that thread. It looks to me, like your tried to run Perl code from a QueueUserWorkItem style thread. A random thread, of which there is a random count of at a single point in time, and the threads come and go randomly, and they run C callbacks randomly. Perl generally can't be fit into that model, since creating and tearing down interps will take too many milliseconds per callback run. There can be 1 interp, and using C/OS level locks, it can be checked out by a random thread, and then returned to a free state. The original OS thread the Perl interp started from goes into a blocking wait of some kind and lets the interp go "thread free" and then random threads pick it up, run a CV, then return to thread free state. I think I have seen a live sample of that on PerlMonks before, maybe by BrowserUk.

    Oh well, I see that is what you did. In a OS thread pool model, you can use just ints into a Perl Array/AV/package @array in 1 Perl thread. It is easier than sending SV/CV/etc *s through the thread pool as opaque with a ref count notch being owned by thread pool queue/3rd party lib, since a random thread callback can't dec the SV * if it reaches 0 and there isn't THE one free interp around anymore since the process is exiting or something. You can't move SV *s between interps. "Free to wrong pool".

    My solution is to never try to move the Perl thread off its original OS thread. Instead use a mechanism (CS locks/queues/linked lists/C structs/C arrays/Windows Message Queue) to deliver the event from the random OS thread to the 1 Perl thread in the process. If the caller of the C callback wants an answer to running the user supplied C callback, a return value for example, the return value in my design is selected on Perl lang level before the async transaction is started. This may not be acceptable in certain kinds async transactions. Of course the C callback can send the event from the thread room, into the many C threads to 1 Perl thread queue, and block in the random C thread until the 1 Perl thread processes the event, then sets a return value, then unblocks the random C thread that originated the event. Assuming the 1 Perl thread isn't CPU maxed out, the response time of the C callback will be max a couple ms.

    BTW, Win32::API's callback support has been fixed to be crash resistant. If you try to run it in an OS thread with no perl interp in Thread Local Storage (AKA thread pool), it will safely complain, not crash, and not try to run any Perl code, see https://github.com/bulk88/perl5-win32-api/blob/master/Callback/Callback.xs#L187.
      Perl generally can't be fit into that model, since creating and tearing down interps will take too many milliseconds per callback run.

      You read too quickly.

      My solution is to never try to move the Perl thread off its original OS thread.

      That implies that the OP -- not me; I didn't construct the problem, just help with the solution -- had a choice. I contend, very strongly -- that he did not.

      In threads, what defines a thread is a 'context', usually abbreviated CXT, and prefixed with xxx_, Eg. MY_CXT; which in turn is just an alias for typedef struct _ithread. The only thing that tie a particular ithread, to a particular OS thread, is that the context (pointer to struct _ithread) is stored in a thread-local storage.

      When using asynchronous IO, the user code has no control over what OSthread will be running when the OS callback to complete the IO.

      And if the 'wrong' OS thread -- ie. *not* the one that created the IO completion callback -- is running when the IO completion callback is called by the OS, then things go belly up (Ie. CRASH!), because none of the perl environment elements -- stash, coderefs, closures, et al. -- are available when the Perl coderef given as the callback, are available if it is called within the context of the wrong thread.

      The *only* way to address that problem is to set the context for the current thread -- at the XS level -- prior to entering the Perl level callback code.

      If that description does not seem correct and unassailable to you, it can only mean that you do not understand the problems inherent is responding to asynchronous callback at the Perl level. So read more and think twice.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        When using asynchronous IO, the user code has no control over what OSthread will be running when the OS callback to complete the IO.

        Not with Kernel32 IO or epoll or select. Ive seen in 3rd party closed source libs, a thread pool is a bandaid when the code can't be audited and fixed of blocking syscalls and high CPU code (parsing, searching, etc). The correct fix is for all blocking syscalls become async IO. All waits on locks become async. High CPU code goes into a separate thread/core/process that reports progress events back to the event loop/dispatcher thread. So when you are lazy, just throw it in threads, if the threads block (and the pool goes empty and the pool event isn't picked up for execution with the timeout period), so what, automatically make more threads. I (a lazy devel) can now call my library "scalable" too on the powerpoint to the suits.

        And if the 'wrong' OS thread -- ie. *not* the one that created the IO completion callback -- is running when the IO completion callback is called by the OS, then things go belly up (Ie. CRASH!), because none of the perl environment elements -- stash, coderefs, closures, et al. -- are available when the Perl coderef given as the callback, are available if it is called within the context of the wrong thread.

        The *only* way to address that problem is to set the context for the current thread -- at the XS level -- prior to entering the Perl level callback code.

        If that description does not seem correct and unassailable to you, it can only mean that you do not understand the problems inherent is responding to asynchronous callback at the Perl level. So read more and think twice.

        I know very well how Perl threads relate to OS threads since I've already done all the mistakes you describe above in the past. It is not mandatory to move Perl threads between OS threads. The asyncs callbacks from random threads can be serialized (the callback thread blocks until the event is serviced by the 1 Perl thread) into 1 Perl thread where the Perl threads spends most of the time sleeping on its event queue (Tk, User32, Wx, whatever). The callbacks taking a ms or 2 longer than a pure C program but so what. The overhead is indistinguishable from using an interpreted language in the first place.

        perlmonk1729's problem is he doesn't know what C data structures in Perl can and can not be accessed between different OS threads and when leading to race condition nightmares.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1053604]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (3)
As of 2024-04-20 12:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found