Forked from
APT Developers / apt
888 commits behind the upstream repository.
-
Zhang Boyang authored
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
Zhang Boyang authoredPreviously, 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
install-progress.h 5.51 KiB
#ifndef PKGLIB_IPROGRESS_H
#define PKGLIB_IPROGRESS_H
#include <apt-pkg/macros.h>
#include <string>
#include <vector>
#include <signal.h>
#include <unistd.h>
namespace APT {
namespace Progress {
class PackageManager;
APT_PUBLIC PackageManager* PackageManagerProgressFactory();
class APT_PUBLIC PackageManager
{
private:
/** \brief dpointer placeholder */
void * const d;
protected:
std::string progress_str;
float percentage;
int last_reported_progress;
public:
PackageManager();
virtual ~PackageManager();
/* Global Start/Stop */
virtual void Start(int /*child_pty*/=-1) {};
virtual void Stop() {};
/* When dpkg is invoked (may happen multiple times for each
* install/remove block
*/
virtual void StartDpkg() {};
virtual pid_t fork() {return ::fork(); };
virtual void Pulse() {};
virtual long GetPulseInterval() {
return 50000000;
};
virtual bool StatusChanged(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string HumanReadableAction);
virtual void Error(std::string /*PackageName*/,
unsigned int /*StepsDone*/,
unsigned int /*TotalSteps*/,
std::string /*ErrorMessage*/) {}
virtual void ConffilePrompt(std::string /*PackageName*/,
unsigned int /*StepsDone*/,
unsigned int /*TotalSteps*/,
std::string /*ConfMessage*/) {}
};
class APT_PUBLIC PackageManagerProgressFd : public PackageManager
{
void * const d;
protected:
int OutStatusFd;
int StepsDone;
int StepsTotal;
void WriteToStatusFd(std::string msg);
public:
explicit PackageManagerProgressFd(int progress_fd);
virtual ~PackageManagerProgressFd();
virtual void StartDpkg() APT_OVERRIDE;
virtual void Stop() APT_OVERRIDE;
virtual bool StatusChanged(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string HumanReadableAction) APT_OVERRIDE;
virtual void Error(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string ErrorMessage) APT_OVERRIDE;
virtual void ConffilePrompt(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string ConfMessage) APT_OVERRIDE;
};
class APT_PUBLIC PackageManagerProgressDeb822Fd : public PackageManager
{
void * const d;
protected:
int OutStatusFd;
int StepsDone;
int StepsTotal;
void WriteToStatusFd(std::string msg);
public:
explicit PackageManagerProgressDeb822Fd(int progress_fd);
virtual ~PackageManagerProgressDeb822Fd();
virtual void StartDpkg() APT_OVERRIDE;
virtual void Stop() APT_OVERRIDE;
virtual bool StatusChanged(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string HumanReadableAction) APT_OVERRIDE;
virtual void Error(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string ErrorMessage) APT_OVERRIDE;
virtual void ConffilePrompt(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string ConfMessage) APT_OVERRIDE;
};
class APT_PUBLIC PackageManagerFancy : public PackageManager
{
void * const d;
private:
APT_HIDDEN static void staticSIGWINCH(int);
static std::vector<PackageManagerFancy*> instances;
static sighandler_t SIGWINCH_orig;
static volatile sig_atomic_t SIGWINCH_flag;
APT_HIDDEN void CheckSIGWINCH();
APT_HIDDEN bool DrawStatusLine();
protected:
void SetupTerminalScrollArea(int nr_rows);
void HandleSIGWINCH(int); // for abi compatibility, do not use
typedef struct {
int rows;
int columns;
} TermSize;
TermSize GetTerminalSize();
sighandler_t old_SIGWINCH; // for abi compatibility, do not use
int child_pty;
public:
PackageManagerFancy();
virtual ~PackageManagerFancy();
virtual void Pulse() APT_OVERRIDE;
virtual void Start(int child_pty=-1) APT_OVERRIDE;
virtual void Stop() APT_OVERRIDE;
virtual bool StatusChanged(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string HumanReadableAction) APT_OVERRIDE;
// return a progress bar of the given size for the given progress
// percent between 0.0 and 1.0 in the form "[####...]"
static std::string GetTextProgressStr(float percent, int OutputSize);
};
class APT_PUBLIC PackageManagerText : public PackageManager
{
void * const d;
public:
virtual bool StatusChanged(std::string PackageName,
unsigned int StepsDone,
unsigned int TotalSteps,
std::string HumanReadableAction) APT_OVERRIDE;
PackageManagerText();
virtual ~PackageManagerText();
};
} // namespace Progress
} // namespace APT
#endif