Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eval procedure doesn't work in the newly created thread. #753

Closed
niyarin opened this issue Mar 13, 2021 · 3 comments
Closed

Eval procedure doesn't work in the newly created thread. #753

niyarin opened this issue Mar 13, 2021 · 3 comments

Comments

@niyarin
Copy link

niyarin commented Mar 13, 2021

When I execute the eval procedure in the newly created thread, the value is not returned.

It worked in ver0.99. It also worked on the REPL.
I'm sorry if I'm wrong.

(import (scheme base) (scheme eval)  (srfi 18))

(let ((thread (make-thread
                (lambda () (eval '(write (cons 1 2))
                                 (environment '(scheme base) '(scheme write)))))))
  (thread-start! thread)
  (thread-join! thread))
@shirok
Copy link
Owner

shirok commented Mar 13, 2021

Wow. Good catch.
It is actually not eval, but an unexpected side effect of changing port structure, though it can be revealed only when number of conditions are met.

  • In 0.9.10 I changed Scm_Port to keep the port name (source file name if it's a file port) in the port attributes, rather than in a separate slot. Port attributes are a general mechanism to associate arbitrary key-value pairs to each ports, and it seemed a good idea to treat port name as one of the attributes.
  • Port attributes can be modified at any time, so its access is mutexed by the lock in each port.
  • That lock is also used while one thread accessing a port.
  • Each thread keeps a parameter current-load-port, which is set during the thread is loading code from a port.
  • When a thread is created, it inherits parameter values from the creator thread.
  • Hence, if a thread is created during loading a script, the created thread shares the same port as current-load-port.
  • Eval in the child thread calls the compiler.
  • The compiler tries to take the name of the current loading port as the source code information.
  • However, the port is locked by the parent thread, since it is still loading the script from it.
  • Deadlock.

I'd say it's a bug, for attribute access needs only be locked during attribute access and doesn't need to coincide with the port access. But this particular situation only occurs when you create a new thread and calls eval while the main thread is still loading from the script. That's why it hasn't been unnoticed.

@shirok
Copy link
Owner

shirok commented Mar 14, 2021

I'll fix this by the next release, but if this gets in your way, one workaround is not to do everything during loading the script file; for example, if you execute the main program via the main procedure, eval is called after the script is loaded so it won't deadlock.

(import (scheme base) (scheme eval) (srfi 18))

(define (main args)
  (let ((thread (make-thread
                 (lambda ()
                   (eval '(write (cons 1 2))
                         (environment '(scheme base) '(scheme write)))))))
    (thread-start! thread)
    (thread-join! thread))
  0)

Note that srfi-22 (the feature that main is called) isn't enabled for R7RS scripts, so you need a special command-line option:

gosh -mr7rs.user script.scm

shirok added a commit that referenced this issue Mar 14, 2021
See #753 for the reason.

This is technically an incompatible change, but port attributes haven't
been made public.

We dropped procedural port attributes.  At this point there's no application,
and it complicates lock management.
@shirok
Copy link
Owner

shirok commented Mar 14, 2021

Fixed in the HEAD.

@shirok shirok closed this as completed Mar 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants