GithubHelp home page GithubHelp logo

Comments (20)

emixa-d avatar emixa-d commented on September 25, 2024 1

Looking at the definition of handle-SIGCHLD, the first paragraph appears to be the case. So, seems like a pure Shepherd bug.

Also, performing Fibers operations inside an async is super skeevy. The Fibers stuff might be in an intermediate state, which usually is invisible to Fibers users but potentially not from asyncs, so now it might be messing things up. Or the async might be run inside a fiber that currently is in the progress of doing a put-message of its own, which put-message was not designed to handle, so that might mess things up. Or perhaps it is even run inside the process monitor, while it is doing (get-message (current-process-monitor)) -- I don't know what would happen then, but I doubt it is anything good.

Really, unless it's a pure operation or something ultra-basic like vector-set! or something that's actually documented to be allowed/supported, you shouldn't be assuming you can simply do things from an async.

Please remove this process-monitor stuff or actually implement & document the prerequisites in Fibers first.

Given how Shepherd is messing around with the API, I'll be responding to future Shepherd/Fibers bug reports that are not easily verifiably to be an actual bug in Fibers (*) with ‘then don't misuse the API’ + close.

(*) a small reproducer (not using Shepherd) should do it

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024 1

Alt., do the pipe trick.

Though I think the main issue here is that the parameterize doesn't cover the root-service, register-services and with-service-register stuff. (The async stuff is problematic, but appears to be something with a low chance of actually going wrong.) iow,you may need to switch with-service-registry with with-process-monitor.

from fibers.

Reepca avatar Reepca commented on September 25, 2024

After a bit of reading Guile's source, it looks like the intent behind thread-local fluids is that they can't be directly manipulated by any guile-side code - that way there's no risk of values being visible in other threads. It also means that there's currently no way of making this particular feature make sense in Fibers. It works with guile-native threads because the setup for them calls guilify_self_2, which sets up the new thread's dynamic_state with an empty set of thread_local_values, and there's no need to ever switch that around because it's part of SCM_I_CURRENT_THREAD, which is different per-thread.

In future versions of Guile it may be possible to make it work, and that'd be nice. So I'll leave this issue open for now, if that's okay.

I still have no clue what's up with issue 1, though.

from fibers.

Habush avatar Habush commented on September 25, 2024

Issue 1 has been solved in the latest version of (I'm using Guile 3.0.2).

from fibers.

karbiv avatar karbiv commented on September 25, 2024

make-thread-local-fluid function seems to be a remnant of 2005-03-08 rewrite by Marius Vollmer.

It's retained in Guile 2.2 release, there was a make-dynamic-state function before. NEWS for 2.2 release:

** `make-dynamic-state'

Use `current-dynamic-state' to get an immutable copy of the current fluid-value associations.

So in this code snippet make-thread-local-fluid should be replaced with make-fluid.
Works correctly with make-fluid in current Guile version, 3.0.5:

Guile thread value: 1337
Fiber 1 value: 1337
Fiber 2 value: 1337
Main thread final value: 1337

Value 42 of some-fluid is visible only in dynamic extent of the first fiber.

2. It would be nice to have the ability to use thread-local variables in fibers, though.

Fiber can be on any random thread when #:parallel? #t argument for spawn-fiber is used, or after work stealing in schedulers. Maybe thread locals could be useful for some interoperability with C libraries.

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

Maybe we could have separate make-thread-local-fluid and make-fiber-local-fluid? I never use thread local fluids though, so I don't know whether this would be useful.

from fibers.

attila-lendvai avatar attila-lendvai commented on September 25, 2024

i think i'm looking at a manifestation of this, or something similar.

it's in Shepherd, the init process of Guix. it's a single threaded program that uses fibers for cooperative multitasking. it has a

(define current-process-monitor
  ;; Channel to communicate with the process monitoring fiber.
  (make-parameter #f))

the symptom is that even though the entire daemon is wrapped in the dynamic extent of a parameterize that sets this fluid, at some point an assert dies because this fluid is #f.

is my expectation valid, namely that if there are no posix threads, and everything happens under the dynamic extent of a parameterize, then i should see the same fluid value throughout my entire codebase? assuming, of course, that nothing sets the parameter besides the initial binding.

what seems to trigger this is the reloading of the shepherd config, which creates a temp module, loads some code into it, and evals it. this code spawns fibers, and some figers are exiting, but all under the parameterize.

$ guile --version
guile (GNU Guile) 3.0.9
name: guile-fibers
version: 1.3.1

also pinging @civodul for this.

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

@attila-lendvai That's not a thread-local fluid (in this case, parameter), but that does sound vaguely like something that could be caused by Fibers useof 'with-dynamic-state/current-dynamic-state'. (Still sounds weird though, will think a little more about it -- as you describe the situation, even if there were posix threads in play, that seems impossible, so I think the actual situation is different.)

I think the bug here is that 'spawn-fiber' does all this with-dynamic-state/current-dynamic-state stuff and I think that stuff should simply be removed (after checking why Fibers does this ‘isolation of fluid and parameter mutations’, to use the docstring's wording, to make sure the cure doesn't cause a new isssue/reintroduce an old issue).

If you want to spawn a fiber with isolated state, you can still do so yourself with little trouble, but AFAIK it is impossible to de-isolate a state ...

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

@attila-lendvai here is some code testing the situation you are describing ... it doesn't reproduce it, I propose minimizing the test case.

(use-modules (fibers) (fibers timers))
(define p (make-parameter #false))
(parameterize ((p #true))
  (run-fibers
  (lambda ()
    (pk (p))
    (spawn-fiber (lambda () (pk (p))))
    (sleep 1))
  #:parallelism 1 #:hz 0)
  

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

Hypothesis: shepherd installs a signal handler, which in turn tries to invoke the process monitor. But the signal was sent to a thread that isn't the main thread (created before the 'parameterize', or even created inside but outside Guile's (ice-9 threads)/SRFI equivalent so Guile doesn't remember where the new thread originated from so the parameter/fluid bindings aren't inherited from the 'parameterize'), and because that other thread doesn't have the binding of your process-monitor parameter, resulting in the issues you noticed.

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

You can test this by (pk (current-thread)) in the main thread, inside the (run-fibers ...) form (should be redundant, but maybe test it just in case), and just before reading the process-monitor parameter.

If the output isn't the same in all cases, then something like the hypothesis might be going on.

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

the symptom is that even though the entire daemon is wrapped in the dynamic extent of a parameterize that sets this fluid,

So, I looked at shepherd.scm (shepherd 0.10.2), and this turns out to be untrue:

        (run-fibers
         (lambda ()
           (with-service-registry

             ;; Register and start the 'root' service.
             (register-services (list root-service))
             (start-service root-service)

             (with-process-monitor
               ;; [...]
               (replace-core-bindings! [...]
               (run-daemon [...])))))

As you can see, the `run-fibers' is not wrapped in a process monitor. Hence, assuming that 'the process monitor is read/invoked from a signal handler, it is quite plausible that it is invoked outside the extend of the with-process-monitor.

Before the run-fibers (not copied), there is also a whole lot of initialisation going on, which might perhaps be capturing the (uninitialised) process monitor.

Even inside the run-fibers, not everything is wrapped in a process monitor: the register-services and start-service isn't.

(Yes, run-daemon is inside the process monitor, but that's a misleading name, the other stuff is also daemon stuff!).

from fibers.

attila-lendvai avatar attila-lendvai commented on September 25, 2024

@emixa-d thank you very much for looking into this!

i'll move the rest of this discussion to the guix mailing list.

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

(To be clear, I think that being able to do 'put-message' from an async would be great, the issue is that this is not yet actually supported & implemented -- it might work but more by accident than anything else.)

from fibers.

attila-lendvai avatar attila-lendvai commented on September 25, 2024

@emixa-d is there any facility through which an async signal handler could tell some fiber in the fiber universe to wake up? the handler could package up the signal into an object, store it somewhere, and tell a fiber to look at this place.

and if there's nothing like this yet, then do you think polling an atomic variable could work?

i'm rather new to scheme/guile/fibers, so feel free to just give me an RTFM pointer... :)

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

@emixa-d is there any facility through which an async signal handler could tell some fiber in the fiber universe to wake up? the handler could package up the signal into an object, store it somewhere, and tell a fiber to look at this place.

I don't think any of this is in the manual.

and if there's nothing like this yet, then do you think polling an atomic variable could work?

Make sure not to poll too long because shepherd disables preemption (maybe insert some '(sleep 0)'? Such spinning grossly inefficient, but in principle it would would work to work-around things ... but inefficient. I guess you could avoid the inefficiency by only polling when something else happens anyway (say, the daemon receives some RPC, a service has started, whatever), sounds kind of unsatisfying though.

Perhaps, with some small adjustments, signal-condition (+ an atomic box for the data)? The implementation of signal-condition (or was it perform-operation itself?) has some support for being run outside a fiber (via POSIX condition stuff) -- while I don't think it expects to be run as an async (e.g., signal handler stuff), I guess it would be straightforward to define a variant signal-condition/no-fibers that always does the POSIX path.

It might even be the case that signal-condition works as-is -- compared to the other Fibers operations stuff, it is quite straightforward -- but that requires a careful look, testing (+ documenting for discoverability and making sure that for future changes, people know not to break that).

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

(Well, signal-condition!, whatever.)

from fibers.

attila-lendvai avatar attila-lendvai commented on September 25, 2024

@emixa-d wow, indeed! i never thought switching them up would make a difference. i only moved the root-service stuff inside the with-process-monitor, but it behaved the same.

thanks for keeping on thinking about this, and proposing an actual fix! :)

from fibers.

emixa-d avatar emixa-d commented on September 25, 2024

from fibers.

attila-lendvai avatar attila-lendvai commented on September 25, 2024

@emixa-d no, your gut feeling was right. since then the fix is already in shepherd: https://git.savannah.gnu.org/cgit/shepherd.git/commit/?id=9be0b7e6fbe3c2e743b5626f4dff7c7bf9becc16

thanks again!

from fibers.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.