mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Nick Peng <pymumu@gmail.com>
To: Nick Peng <pymumu@gmail.com>, musl@lists.openwall.com
Subject: Re: [musl] BUG: Calling readdir/dirfd after vfork will cause deadlock.
Date: Mon, 27 Jun 2022 12:05:41 +0800	[thread overview]
Message-ID: <CALkM5nttiPx75y3SZeGfh65LG_e7vngPNnY4KyHttO0qR-R3og@mail.gmail.com> (raw)
In-Reply-To: <20220625125110.GV1320090@port70.net>

[-- Attachment #1: Type: text/plain, Size: 5440 bytes --]

The feature I want to achieve is to close all file handles after fork to
avoid file handles being inherited to child processes.

We have a component which is used in a process that uses too much memory
(about 50BG) and uses too many file handles(about 100,000 files).
In order to avoid file handles inheriting from child processes, we
implemented a API like system,close all file handles after vfork.
We can't close all file handles by iterating over all file handles number,
because the maximum number of files limit is set very large, the
performance of this method is too poor.
And we can't use fork, fork will fail because of vm.overcommit_memory.
In order to optimize this, the method we used is to read the file handes in
/proc/self/fd directory and close the file handles one by one.

The component is based on glibc, currently this program runs for about 10
years without deadlock.
Recently, this component is used in musl-based embedded systems, and it
hangs often.

After reading the vfork manual and the guidance you gave, i understand
calling readdir after vfork is problematic. and I also learned that I can
call getent64 to achieve this
but what I want to say is that, based on glibc, after calling readdir after
vfork, there is no deadlock problem at present.

more information: I googled and found this(https://lwn.net/Articles/789023/),
probably the best solution, but it seems that the required kernel version
is too new for my program to work with.

However, I think my problem is solved anyway, thank you all.

On Sun, Jun 26, 2022 at 2:49 AM Szabolcs Nagy <nsz@port70.net> wrote:

> * Nick Peng <pymumu@gmail.com> [2022-06-25 11:40:17 +0800]:
> > Description:  After vfork, calling functions such as readdir/dirfd may
> > cause deadlock. GNU C is OK.
>
> why do you think "GNU C is OK"? is this from some real software?
>
> opendir after vfork is documented to be invalid in glibc:
>
> https://www.gnu.org/software/libc/manual/html_mono/libc.html#Low_002dlevel-Directory-Access
>
> the standard is actually much stricter than the glibc manual:
> posix conforming code must not call any libc api after vfork
> other than _exit or the exec* familiy of functions.
> (as-safe is not enough, but opendir is not even as-safe)
>
> since the example is multi-threaded even using fork would
> be invalid, but i think both musl and glibc makes that work
> (as an extension to the standard).
>
>
> >                      Also tested on x86-64 with musl, no deadlock, but
> > seems never exit, slower than GNU C.
> > Version: latest, musl-1.2.3
> > OS: debian bullseye 64bit OS. and asus router
> > CPU: raspberrypi aarch64, mips32
> > Reproduce Code:
> >
> > #include <dirent.h>
> > #include <pthread.h>
> > #include <stdint.h>
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <sys/types.h>
> > #include <sys/wait.h>
> > #include <unistd.h>
> > #include <string.h>
> >
> > pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
> > pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> >
> > struct tlog_log *logs = NULL;
> > int do_exit = 0;
> >
> > void *test(void *arg)
> > {
> >     int i = 0;
> >
> >     for (i = 0; i < 10000000; i++) {
> >         char *b = malloc(4096);
> >         memset(b, 0, 4096);
> >         free(b);
> >     }
> >     do_exit = 1;
> >     return NULL;
> > }
> >
> > void lockfunc()
> > {
> >     char path_name[4096];
> >     DIR *dir = NULL;
> >     struct dirent *ent;
> >
> >     snprintf(path_name, sizeof(path_name), "/proc/self/fd/");
> >     dir = opendir(path_name);
> >     if (dir == NULL) {
> >         goto errout;
> >     }
> >
> >     while ((ent = readdir(dir)) != NULL) {
> >     }
> >
> >     closedir(dir);
> >
> >     return;
> > errout:
> >     if (dir) {
> >         closedir(dir);
> >     }
> >
> >     return;
> > }
> >
> > void *test_fork(void *arg)
> > {
> >     int count = 0;
> >     while (do_exit == 0) {
> >         printf("test fork count %d\n", count++);
> >         int pid = vfork();
> >         if (pid < 0) {
> >             return NULL;
> >         } else if (pid == 0) {
> >             lockfunc();
> >             _exit(0);
> >         }
> >
> >         int status;
> >         waitpid(pid, &status, 0);
> >     }
> >
> >     return NULL;
> > }
> >
> > int main(int argc, char *argv[])
> > {
> >     pthread_attr_t attr;
> >     pthread_t threads[10];
> >     pthread_t fork_test;
> >     int i;
> >     int ret;
> >
> >     pthread_attr_init(&attr);
> >
> >     ret = pthread_create(&fork_test, &attr, test_fork, NULL);
> >
> >     for (i = 0; i < 10; i++) {
> >         ret = pthread_create(&threads[i], &attr, test, NULL);
> >         if (ret != 0) {
> >             return 1;
> >         }
> >     }
> >
> >     for (i = 0; i < 10; i++) {
> >         void *retval = NULL;
> >         pthread_join(threads[i], &retval);
> >     }
> >
> >     void *retval = NULL;
> >     pthread_join(fork_test, &retval);
> >     printf("exit\n");
> >     getchar();
> >     return 0;
> > }
> >
> >
> > Log:
> > pi@raspberrypi:~/code/tinylog/test $ ./test
> > test fork count 0
> > test fork count 1   <-- lock here
> > ^C
> >
> > gdb backtrace:
> > x0000000000409524 in __lock ()
> > (gdb) bt
> > #0  0x0000000000409524 in __lock ()
> > #1  0x0000000000406278 in __libc_malloc_impl ()
>

[-- Attachment #2: Type: text/html, Size: 7191 bytes --]

  reply	other threads:[~2022-06-27  6:30 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-25  3:40 Nick Peng
2022-06-25 12:51 ` Szabolcs Nagy
2022-06-27  4:05   ` Nick Peng [this message]
2022-06-27 10:38     ` Laurent Bercot
2022-06-27 14:21     ` Rich Felker
2022-06-27 14:29     ` Markus Wichmann
2022-06-27  7:42   ` Florian Weimer
2022-06-27  8:37     ` Szabolcs Nagy
2022-06-27  9:23       ` Florian Weimer
2022-06-27 17:33         ` Szabolcs Nagy
2022-06-25 12:56 ` Alex Xu (Hello71)
2022-06-27  7:44   ` Florian Weimer
2022-06-27 12:28     ` Alex Xu (Hello71)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CALkM5nttiPx75y3SZeGfh65LG_e7vngPNnY4KyHttO0qR-R3og@mail.gmail.com \
    --to=pymumu@gmail.com \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).