Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
gh-35195: Workaround for an ecl race in maxima init 
    
### πŸ“š Description

When maxima is initialized a bug in ecl implementation of
`ensure-directories-exist` might result in a runtime error.

As a workaround, in case we get a runtime error we use python to create
the directory and continue with maxima initialization.

Note that for normal usage the directory will already exist within the
user's `DOT_SAGE` so this code will almost never run. However, when
running doctests on CI this occasionally triggers.

#### New doctest

The first commit introduces a doctest to try to catch this race.
We run a new instance of sage in a subprocess to ensure maxima is
not already initialized. We use a temporary `MAXIMA_USERDIR` so its
empty,
and we try to initialize maxima twice in parallel to entice the race.

This temporary dir is placed within `DOT_SAGE` so it is easy
to try different filesystems.

The bug triggers more frequently if `DOT_SAGE` is in a high
latency filesystem (e.g. sshfs on a non-local host).

Closes #26968.

### πŸ“ Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [x] I have made sure that the title is self-explanatory and the
description concisely explains the PR.
- [x] I have linked an issue or discussion.
- [x] I have created tests covering the changes.
    
URL: #35195
Reported by: Gonzalo TornarΓ­a
Reviewer(s): Gonzalo TornarΓ­a, Matthias KΓΆppe
  • Loading branch information
Release Manager committed Mar 24, 2023
2 parents bd8ede6 + 0b13dfc commit e1cb236
Showing 1 changed file with 37 additions and 1 deletion.
38 changes: 37 additions & 1 deletion src/sage/interfaces/maxima_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,26 @@
sage: bar == foo
True
TESTS:
Check our workaround for a race in ecl works, see :trac:`26968`.
We use a temporary `MAXIMA_USERDIR` so it's empty; we place it
in `DOT_SAGE` since we expect it to have more latency than `/tmp`.
sage: import tempfile, subprocess
sage: tmpdir = tempfile.TemporaryDirectory(dir=DOT_SAGE)
sage: _ = subprocess.run(['sage', '-c', # long time
....: f'''
....: import os
....: os.environ["MAXIMA_USERDIR"] = "{tmpdir.name}"
....: if not os.fork():
....: import sage.interfaces.maxima_lib
....: else:
....: import sage.interfaces.maxima_lib
....: os.wait()
....: '''])
sage: tmpdir.cleanup()
"""

# ****************************************************************************
Expand Down Expand Up @@ -116,7 +136,23 @@
ecl_eval("(setq $nolabels t))")
ecl_eval("(defvar *MAXIMA-LANG-SUBDIR* NIL)")
ecl_eval("(set-locale-subdir)")
ecl_eval("(set-pathnames)")

try:
ecl_eval("(set-pathnames)")
except RuntimeError:
# Recover from :trac:`26968` by creating `*maxima-objdir*` here.
# This cannot be done before calling `(set-pathnames)` since
# `*maxima-objdir*` is computed there.
# We use python `os.makedirs()` which is immune to the race.
# Using `(ensure-directories-exist ...)` in lisp would be
# subject to the same race condition and since `*maxima-objdir*`
# has multiple components this is quite plausible to happen.
maxima_objdir = ecl_eval("*maxima-objdir*").python()[1:-1]
import os
os.makedirs(maxima_objdir, exist_ok=True)
# Call `(set-pathnames)` again to complete its job.
ecl_eval("(set-pathnames)")

ecl_eval("(defun add-lineinfo (x) x)")
ecl_eval('(defun principal nil (cond ($noprincipal (diverg)) ((not pcprntd) (merror "Divergent Integral"))))')
ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539)
Expand Down

0 comments on commit e1cb236

Please sign in to comment.