binutils-gdb/gdbsupport/scoped_ignore_sigttou.h
Pedro Alves 336b30e58a Don't call sigtimedwait for scoped_ignore_sigttou
Because SIGTTOU is sent to the whole process instead of to a specific
thread, consuming a pending SIGTTOU in the destructor of
scoped_ignore_sigttou could consume a SIGTTOU signal raised due to
actions done by some other thread.  Simply avoid sigtimedwait in
scoped_ignore_sigttou, thus plugging the race.  This works because we
know that when the thread writes to the terminal and the signal is
blocked, the kernel does not raise the signal at all.

Tested on GNU/Linux, Solaris 11 and FreeBSD.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <pedro@palves.net>

	* scoped_ignore_signal.h (scoped_ignore_signal): Add
	ConsumePending template parameter.
	(scoped_ignore_signal::~scoped_ignore_signal): Skip calling
	sigtimedwait if ConsumePending is false.
	(scoped_ignore_sigpipe): Initialize with ConsumePending=true.
	* scoped_ignore_sigttou.h (scoped_ignore_sigttou)
	<m_ignore_signal>: Initialize with ConsumePending=false.

Change-Id: I92f754dbc45c45819dce2ce68b8c067d8d5c61b1
2021-06-17 19:39:08 +01:00

88 lines
2.0 KiB
C++

/* Support for signoring SIGTTOU.
Copyright (C) 2003-2021 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef SCOPED_IGNORE_SIGTTOU_H
#define SCOPED_IGNORE_SIGTTOU_H
#include "gdbsupport/scoped_ignore_signal.h"
#include "gdbsupport/job-control.h"
#ifdef SIGTTOU
/* Simple wrapper that allows lazy initialization / destruction of T.
Slightly more efficient than gdb::optional, because it doesn't
carry storage to track whether the object has been initialized. */
template<typename T>
class lazy_init
{
public:
void emplace ()
{
new (&m_u.obj) T ();
}
void reset ()
{
m_u.obj.~T ();
}
private:
union u
{
/* Must define ctor/dtor if T has non-trivial ctor/dtor. */
u () {}
~u () {}
T obj;
} m_u;
};
/* RAII class used to ignore SIGTTOU in a scope. This isn't simply
scoped_ignore_signal<SIGTTOU> because we want to check the
`job_control' global. */
class scoped_ignore_sigttou
{
public:
scoped_ignore_sigttou ()
{
if (job_control)
m_ignore_signal.emplace ();
}
~scoped_ignore_sigttou ()
{
if (job_control)
m_ignore_signal.reset ();
}
DISABLE_COPY_AND_ASSIGN (scoped_ignore_sigttou);
private:
lazy_init<scoped_ignore_signal<SIGTTOU, false>> m_ignore_signal;
};
#else
using scoped_ignore_sigttou = scoped_ignore_signal_nop;
#endif
#endif /* SCOPED_IGNORE_SIGTTOU_H */