Мне нужен список асинхронно-безопасных функций от glibc

Оболочки не syscall, но что-то вроде snprintf(), dprintf()

4 ответа

Решение

Наконец-то последние версии man 7 signal-safety содержит заинтересованный список: signal-safety.7.html

Я уверен, что вы должны увидеть документацию

Редактировать: Как насчет этого списка тогда?

От man signal:

NOTES

   The effects of this call in a multi-threaded process are unspecified.


   The routine handler must be very careful,  since  processing  elsewhere
   was interrupted at some arbitrary point. POSIX has the concept of "safe
   function".  If a signal interrupts  an  unsafe  function,  and  handler
   calls  an  unsafe  function, then the behavior is undefined. Safe func-
   tions are listed explicitly in the various standards.  The POSIX.1-2003
   list is

   _Exit()  _exit()  abort()  accept()  access()  aio_error() aio_return()
   aio_suspend() alarm() bind() cfgetispeed() cfgetospeed()  cfsetispeed()
   cfsetospeed() chdir() chmod() chown() clock_gettime() close() connect()
   creat() dup() dup2() execle() execve() fchmod() fchown() fcntl() fdata-
   sync()   fork()   fpathconf()  fstat()  fsync()  ftruncate()  getegid()
   geteuid() getgid() getgroups() getpeername() getpgrp()  getpid()  getp-
   pid()   getsockname()  getsockopt()  getuid()  kill()  link()  listen()
   lseek() lstat()  mkdir()  mkfifo()  open()  pathconf()  pause()  pipe()
   poll()  posix_trace_event()  pselect() raise() read() readlink() recv()
   recvfrom()  recvmsg()  rename()  rmdir()  select()  sem_post()   send()
   sendmsg()  sendto()  setgid()  setpgid() setsid() setsockopt() setuid()
   shutdown()  sigaction()  sigaddset()  sigdelset()  sigemptyset()   sig-
   fillset()  sigismember() signal() sigpause() sigpending() sigprocmask()
   sigqueue() sigset() sigsuspend() sleep() socket()  socketpair()  stat()
   symlink()  sysconf()  tcdrain()  tcflow() tcflush() tcgetattr() tcgetp-
   grp() tcsendbreak() tcsetattr() tcsetpgrp()  time()  timer_getoverrun()
   timer_gettime()   timer_settime()   times()  umask()  uname()  unlink()
   utime() wait() waitpid() write().

   According to POSIX, the behaviour of a process is  undefined  after  it
   ignores  a  SIGFPE, SIGILL, or SIGSEGV signal that was not generated by
   the kill(2) or the raise(3) functions.  Integer division  by  zero  has
   undefined result.  On some architectures it will generate a SIGFPE sig-
   nal.  (Also dividing the most  negative  integer  by  -1  may  generate
   SIGFPE.)  Ignoring this signal might lead to an endless loop.

   See  sigaction(2)  for  details  on what happens when SIGCHLD is set to
   SIG_IGN.

   The use of sighandler_t is a GNU extension.  Various versions  of  libc
   predefine  this  type;  libc4  and  libc5  define  SignalHandler, glibc
   defines sig_t and, when _GNU_SOURCE is defined, also sighandler_t.

Кажется, это трудно определить, так как вы не знаете, какую случайную небезопасную функцию может вызвать библиотечная подпрограмма. Список также может отличаться в разных версиях glibc или в другой Unix-подобной системе. Похоже, вам нужно проанализировать множество стеков вызовов, чтобы найти ответ, и даже это может быть немного шатким от версии к версии, от дистрибутива к дистрибутиву.

Возможно, вы не ищете альтернативных подходов к проектированию, но кажется, что лучшая стратегия была бы такой: если в вашей программе есть цикл обработки событий, сделайте обработчик сигналов очень глупым и просто установите какое-то состояние, которое будет обрабатывать цикл обработки событий. Таким образом, вы делаете значимую работу за пределами обработчика сигнала.

Пример: допустим, у вас есть poll() где-то петля Может быть, вы могли бы включить канал, в который обработчик сигнала может записывать. Тогда poll() Цикл делает некоторую нетривиальную работу, основанную на том, чтобы быть сигнализированной этим.

Мне это нужно в обработчике SIGSEGV ПОСЛЕ сбоя приложения.

Я хочу раскрутить стек при сбое

Если вы пытаетесь захватить трассировку стека:

  • типично abort вызовет дамп ядра, который можно запустить через отладчик для получения трассировки стека.

  • В качестве альтернативы, грубый (но безопасный для сигнала) способ сделать это будет fork а также exec отдельная утилита (например, "pstack") для вывода трассировки стека сбойной задачи. когда exec-ing (после forkв ребенке), вам нужно будет передать идентификатор процесса с помощью getppid; и в родительском вам нужно wait чтобы закончить, прежде чем звонить abort,

С другой стороны, если вы пытаетесь выполнить "чистый" выход после SIGSEGV (например, обеспечить вызов деструкторов C++ и т. Д.), То вы должны быть предупреждены, что POSIX говорит:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html:

Поведение процесса не определено после того, как он игнорирует сигнал SIGFPE, SIGILL, SIGSEGV или SIGBUS, который не был сгенерирован kill(), sigqueue() или Повышать ().

и http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html:

Поведение процесса не определено после того, как он нормально возвращается из функции перехвата сигнала для сигнала SIGBUS, SIGFPE, SIGILL или SIGSEGV, который не был сгенерирован kill(), sigqueue() или Повышать ().

Другие вопросы по тегам