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

glibc deprecated some stuff, leading to warnings #4183

Closed
faho opened this issue Jul 4, 2017 · 8 comments
Closed

glibc deprecated some stuff, leading to warnings #4183

faho opened this issue Jul 4, 2017 · 8 comments
Labels
Milestone

Comments

@faho
Copy link
Member

faho commented Jul 4, 2017

In glibc 2.25, a few things we use are marked as deprecated. On my system, this leads to the only remaining compiler warnings.

The full list:

@faho faho added the cleanup label Jul 4, 2017
@faho faho added this to the fish-future milestone Jul 4, 2017
@faho
Copy link
Member Author

faho commented Jul 4, 2017

Urgh, the sys_errlist stuff is annoying - see #1830.

@krader1961
Copy link
Contributor

krader1961 commented Jul 4, 2017

Note that sys_errlist and sys_nerr have been implicitly deprecated for nearly twenty years. It sucks that strerror is not fork safe. If we can't come up with a better solution I recommend calling strerror for all possible errno values and caching the results as soon as we've initialized the environment (in particular the locale subsystem) but before doing anything that would fork.

A solution I've pondered for this type of problem is an internal RPC mechanism. That would allow the child side of a fork to ask a RPC thread in the main fish process (via a fifo or anonymous unix domain socket) to do something that might acquire a lock and get the results back. This would be a non-trivial amount of work to implement but would allow us to simplify the code in other ways such as eliminating debug_safe(). However, doing so in a manner that could be used without fear of deadlock on the child side of a fork is going to be a challenge.

A far simpler solution is to use a barrier to ensure all threads are quiescent before calling fork/spawn. The child process is then free to call malloc, strerror, etc. Yes, I know we generally want to avoid blocking on a thread completing an action. But we have very few threads and none are likely to cause a delay in completing the fork/spawn. If we do have such a thread it is generally trivial to add barrier checks in its inner loop(s) to keep the latency low. The theoretical problem with this approach is that threads created "behind our back" by some library function throws a monkey wrench into the scheme. But we're unlikely to use an API that does so and I think the benefits of this approach outweigh the risks.

@krader1961
Copy link
Contributor

Note that @ridiculousfish has already proposed something similar to my preferred solution in our pthread manifesto:

However, this is certainly a fragile area so bugs here are likely. fish has no long-running threads, and so fish can also be put into a mode where it waits for its threads to exit before calling fork. This should improve safety, but may re-introduce fish 1.x's slowdowns on slow filesystems.

However, note that what I'm proposing does not involve waiting for those threads to exit. I am proposing that we introduce barriers where we block further execution of all threads, other than the main thread, when we need to fork/spawn until the fork/spawn has been done. Thus ensuring that the child process inherits a state that should be free of mutexes held that could result in a deadlock.

@mqudsi
Copy link
Contributor

mqudsi commented Jul 30, 2017

I haven't looked into glibc's implementation of the XSI-compliant version of strerror_r, but can we just wrap it in a function that obtains a named semaphore, clones the contents to a wcstring, and returns the result? There's no need for it to be fast, it's only used in error-handling code.

@krader1961
Copy link
Contributor

@mqudsi: By "named" semaphore do you mean a mutex that is stored in a page of memory shared by the parent and child process? If no then your solution doesn't work. And if yes then I think my proposal is simpler and more general.

@mqudsi
Copy link
Contributor

mqudsi commented Jul 31, 2017

@krader1961 I meant using sem_open with a statically allocated guid as the name; but that would only work presuming all uses of the function take place pre-fork/post-exec. If the mutex has already been opened by the parent process at startup, the calls to sem_open and sem_wait should be allocation-free (and refer to the same semaphore).

It probably wouldn't be too hard to wrap all calls to lock/unlock in a function that increments or decrements some global "obtained mutexes" count and have any fork calls block until that value is zero (condition variable + another mutex).

But I have a different question: what's the reason behind the mix of threads and fork? If you limit forking to a single thread (not necessarily the main thread) used to spawn external processes (so never fork without a more-or-less-immediate exec), can you not avoid the issue entirely? I wonder if it would be too difficult to eliminate non-exec forks with threads that call the respective functions and sidestep the issue entirely.

@krader1961
Copy link
Contributor

But I have a different question: what's the reason behind the mix of threads and fork?

I don't know as I've only been contributing since October 2015. @ridiculousfish may have insight into that question. If I had to guess I would hypothesize that it's the result of the original C (not C++) implementation not using threads. Then when it was rewritten in C++ support for threads was added so that features like history based autosuggestions don't block the user input thread. But the thread implementation was done organically to minimize changes to the existing code that spawns jobs.

@faho
Copy link
Member Author

faho commented Jan 3, 2019

Okay, I now made the readdir change for #5458.

aaptel added a commit to aaptel/fish-shell that referenced this issue May 15, 2020
strerror is not thread-safe and strerror_r is not async-safe (see
man signal-safety) glibc strerror_r can hang in certain real-world
scenarios. (cf github issues fish-shell#472, fish-shell#1830, fish-shell#4183)

To work around that, we previously used the underlying
structures (_sys_err tables) but these are getting deprecated:

    $ make
    ld: libfishlib.a(wutil.cpp.o): in function `safe_strerror(int)':
    wutil.cpp:307: warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead
    ld: wutil.cpp:307: warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
    ld: libfishlib.a(wutil.cpp.o): in function `safe_strerror(int)':
    wutil.cpp:307: warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead

This new solution pre-generates a read-only list of messages at
startup which can be safely returned.

Since caching INT_MAX values is pretty big, let's look at various OS
maximum value for errno:

- Linux [1-133]
  https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno.h

- FreeBSD (userspace visible) [1-97]
  https://github.com/freebsd/freebsd/blob/master/sys/sys/errno.h

- OpenBSD (userspace visible) [1-95]
  https://github.com/openbsd/src/blob/master/sys/sys/errno.h

- Apple (userspace visible) [1-88]
  https://opensource.apple.com/source/xnu/xnu-201/bsd/sys/errno.h.auto.html

- Solaris [1-151]
  http://fxr.watson.org/fxr/source/common/sys/errno.h?v=OPENSOLARIS

We are settling on 200 for good measure.
faho added a commit to faho/fish-shell that referenced this issue Aug 19, 2021
This no longer works on new glibcs because they removed sys_errlist.

So just hardcode the relevant errno messages (and phrase them better).

Fixes fish-shell#4183.
@faho faho mentioned this issue Aug 19, 2021
2 tasks
@faho faho closed this as completed in d4f7e25 Aug 20, 2021
@zanchey zanchey modified the milestones: fish-future, fish 3.4.0 Aug 24, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants