summaryrefslogtreecommitdiff
path: root/apt-pkg/install-progress.cc
diff options
context:
space:
mode:
authorZhang Boyang <zhangboyang.id@gmail.com>2021-12-02 00:21:48 +0800
committerZhang Boyang <zhangboyang.id@gmail.com>2021-12-19 16:24:47 +0800
commitec27853181d898f738ad20fed00f37a00d1d09c3 (patch)
tree325ed899f0e0118bd52584f4e5e274ec74d3b49b /apt-pkg/install-progress.cc
parent2662f6f255a2f1fee25632dc7666d4153bf5248c (diff)
Fix incorrect SIGWINCH handling
Previously, status line is redrawn in signal handler. However, the drawing code make heavy use of std::string and other syscalls, which may not be async-signal-safe. This will cause deadlock, overwritten errno, even silent memory corruption. This patch implemented Anders Kaseorg's idea. The signal handler will only set a flag, which is async-signal-safe, and actual redrawing will be deferred to PackageManagerFancy::Pulse(). Note that the virtual function PackageManagerFancy::Pulse() already exists in base class but newly overridden in PackageManagerFancy, so the ABI compatibility should be OK. However, existing compiled programs may not aware of this new function and continue to use old Pulse() if compiler had done heavy optimization. Fortunately this is not too harmful because this will only cause status line not redrawing, which may consider acceptable. Closes: #852757
Diffstat (limited to 'apt-pkg/install-progress.cc')
-rw-r--r--apt-pkg/install-progress.cc34
1 files changed, 26 insertions, 8 deletions
diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc
index aadd28e51..8a6d87cd2 100644
--- a/apt-pkg/install-progress.cc
+++ b/apt-pkg/install-progress.cc
@@ -222,22 +222,42 @@ PackageManagerFancy::PackageManagerFancy()
: d(NULL), child_pty(-1)
{
// setup terminal size
- old_SIGWINCH = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
+ if (instances.empty())
+ SIGWINCH_orig = signal(SIGWINCH, PackageManagerFancy::staticSIGWINCH);
instances.push_back(this);
}
std::vector<PackageManagerFancy*> PackageManagerFancy::instances;
+sighandler_t PackageManagerFancy::SIGWINCH_orig;
+volatile sig_atomic_t PackageManagerFancy::SIGWINCH_flag = 0;
PackageManagerFancy::~PackageManagerFancy()
{
instances.erase(find(instances.begin(), instances.end(), this));
- signal(SIGWINCH, old_SIGWINCH);
+ if (instances.empty())
+ signal(SIGWINCH, SIGWINCH_orig);
}
void PackageManagerFancy::staticSIGWINCH(int signum)
{
- std::vector<PackageManagerFancy *>::const_iterator I;
- for(I = instances.begin(); I != instances.end(); ++I)
- (*I)->HandleSIGWINCH(signum);
+ SIGWINCH_flag = 1;
+}
+
+void PackageManagerFancy::CheckSIGWINCH()
+{
+ if (SIGWINCH_flag)
+ {
+ SIGWINCH_flag = 0;
+ int errsv = errno;
+ int const nr_terminal_rows = GetTerminalSize().rows;
+ SetupTerminalScrollArea(nr_terminal_rows);
+ DrawStatusLine();
+ errno = errsv;
+ }
+}
+
+void PackageManagerFancy::Pulse()
+{
+ CheckSIGWINCH();
}
PackageManagerFancy::TermSize
@@ -296,9 +316,7 @@ void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows)
void PackageManagerFancy::HandleSIGWINCH(int)
{
- int const nr_terminal_rows = GetTerminalSize().rows;
- SetupTerminalScrollArea(nr_terminal_rows);
- DrawStatusLine();
+ // for abi compatibility, do not use
}
void PackageManagerFancy::Start(int a_child_pty)