Bug 1658084 - Avoid creating a mozilla::OffTheBooksMutex in a static initializer, r=emilio,mccr8

Differential Revision: https://phabricator.services.mozilla.com/D95660
This commit is contained in:
Nika Layzell 2020-11-04 18:56:13 +00:00
Родитель 1825576064
Коммит 188a162ad4
3 изменённых файлов: 45 добавлений и 60 удалений

Просмотреть файл

@ -44,32 +44,21 @@ static bool LoadCupsFunc(PRLibrary*& lib, FuncT*& dest,
return true;
}
bool nsCUPSShim::Init() {
mozilla::OffTheBooksMutexAutoLock lock(mInitMutex);
if (mInited) {
return true;
}
nsCUPSShim::nsCUPSShim() {
mCupsLib = PR_LoadLibrary(gCUPSLibraryName);
if (!mCupsLib) {
return false;
return;
}
// This is a macro so that it could also load from libcups if we are configured
// to use it as a compile-time dependency.
// This is a macro so that it could also load from libcups if we are
// configured to use it as a compile-time dependency.
# define CUPS_SHIM_LOAD(NAME) \
if (!LoadCupsFunc(mCupsLib, NAME, #NAME)) return false;
if (!LoadCupsFunc(mCupsLib, NAME, #NAME)) return;
CUPS_SHIM_ALL_FUNCS(CUPS_SHIM_LOAD)
# undef CUPS_SHIM_LOAD
mInited = true;
return true;
}
#else // CUPS_SHIM_RUNTIME_LINK
bool nsCUPSShim::Init() {
mInited = true;
return true;
// Set mInitOkay only if all cups functions are loaded successfully.
mInitOkay = true;
}
#endif

Просмотреть файл

@ -18,10 +18,15 @@
struct PRLibrary;
/* Note: this class relies on static initialization. */
class nsCUPSShim {
public:
bool EnsureInitialized() { return mInited || Init(); }
#ifdef CUPS_SHIM_RUNTIME_LINK
nsCUPSShim();
bool InitOkay() { return mInitOkay; }
#else
nsCUPSShim() = default;
bool InitOkay() { return true; }
#endif
/**
* Function pointers for supported functions. These are only
@ -60,7 +65,7 @@ class nsCUPSShim {
#ifdef CUPS_SHIM_RUNTIME_LINK
// Define a single field which holds a function pointer.
# define CUPS_SHIM_FUNC_DECL(X) decltype(::X)* X;
# define CUPS_SHIM_FUNC_DECL(X) decltype(::X)* X = nullptr;
#else
// Define a static constexpr function pointer. GCC can sometimes optimize
// away the pointer fetch for this.
@ -70,25 +75,10 @@ class nsCUPSShim {
CUPS_SHIM_ALL_FUNCS(CUPS_SHIM_FUNC_DECL)
#undef CUPS_SHIM_FUNC_DECL
private:
/**
* Initialize this object. Attempt to load the CUPS shared
* library and find function pointers for the supported
* functions (see below).
* @return false if the shared library could not be loaded, or if
* any of the functions could not be found.
* true for successful initialization.
*/
bool Init();
// We can try to get initialized from multiple threads at the same time, this
// boolean and the mutex below make it safe.
//
// The boolean can't be Relaxed, because it guards our function pointers.
mozilla::Atomic<bool, mozilla::ReleaseAcquire> mInited{false};
#ifdef CUPS_SHIM_RUNTIME_LINK
mozilla::OffTheBooksMutex mInitMutex{"nsCUPSShim::mInitMutex"};
PRLibrary* mCupsLib;
private:
bool mInitOkay = false;
PRLibrary* mCupsLib = nullptr;
#endif
};

Просмотреть файл

@ -10,7 +10,13 @@
#include "nsString.h"
#include "prenv.h"
static nsCUPSShim sCupsShim;
// Use a local static to initialize the CUPS shim lazily, when it's needed.
// This is used in order to avoid a global constructor.
static nsCUPSShim& CupsShim() {
static nsCUPSShim sCupsShim;
return sCupsShim;
}
using PrinterInfo = nsPrinterListBase::PrinterInfo;
/**
@ -23,8 +29,8 @@ static void GetDisplayNameForPrinter(const cups_dest_t& aDest,
// while GTK clients expect non-prettified names.
// If you change this, please change NamedPrinter accordingly.
#ifdef XP_MACOSX
const char* displayName =
sCupsShim.cupsGetOption("printer-info", aDest.num_options, aDest.options);
const char* displayName = CupsShim().cupsGetOption(
"printer-info", aDest.num_options, aDest.options);
if (displayName) {
CopyUTF8toUTF16(MakeStringSpan(displayName), aName);
}
@ -67,7 +73,7 @@ static int CupsDestCallback(void* user_data, unsigned aFlags,
cups_dest_t* ownedDest = nullptr;
mozilla::DebugOnly<const int> numCopied =
sCupsShim.cupsCopyDest(aDest, 0, &ownedDest);
CupsShim().cupsCopyDest(aDest, 0, &ownedDest);
MOZ_ASSERT(numCopied == 1);
nsString name;
@ -79,12 +85,12 @@ static int CupsDestCallback(void* user_data, unsigned aFlags,
}
nsTArray<PrinterInfo> nsPrinterListCUPS::Printers() const {
if (!sCupsShim.EnsureInitialized()) {
if (!CupsShim().InitOkay()) {
return {};
}
nsTArray<PrinterInfo> printerInfoList;
if (!sCupsShim.cupsEnumDests(
if (!CupsShim().cupsEnumDests(
CUPS_DEST_FLAGS_NONE,
0 /* timeout, 0 timeout shouldn't be a problem since we are masking
CUPS_PRINTER_DISCOVERED */
@ -100,14 +106,14 @@ nsTArray<PrinterInfo> nsPrinterListCUPS::Printers() const {
RefPtr<nsIPrinter> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo) const {
return mozilla::MakeRefPtr<nsPrinterCUPS>(
mCommonPaperInfo, sCupsShim, std::move(aInfo.mName),
mCommonPaperInfo, CupsShim(), std::move(aInfo.mName),
static_cast<cups_dest_t*>(aInfo.mCupsHandle));
}
Maybe<PrinterInfo> nsPrinterListCUPS::PrinterByName(
nsString aPrinterName) const {
Maybe<PrinterInfo> rv;
if (!sCupsShim.EnsureInitialized()) {
if (!CupsShim().InitOkay()) {
return rv;
}
@ -123,26 +129,26 @@ Maybe<PrinterInfo> nsPrinterListCUPS::PrinterByName(
nsAutoCString printerName;
CopyUTF16toUTF8(aPrinterName, printerName);
cups_dest_t* printers = nullptr;
const auto numPrinters = sCupsShim.cupsGetDests(&printers);
const auto numPrinters = CupsShim().cupsGetDests(&printers);
for (auto i : mozilla::IntegerRange(0, numPrinters)) {
const char* const displayName = sCupsShim.cupsGetOption(
const char* const displayName = CupsShim().cupsGetOption(
"printer-info", printers[i].num_options, printers[i].options);
if (printerName == displayName) {
// The second arg to sCupsShim.cupsCopyDest is called num_dests, but
// The second arg to CupsShim().cupsCopyDest is called num_dests, but
// it actually copies num_dests + 1 elements.
sCupsShim.cupsCopyDest(printers + i, 0, &printer);
CupsShim().cupsCopyDest(printers + i, 0, &printer);
break;
}
}
sCupsShim.cupsFreeDests(numPrinters, printers);
CupsShim().cupsFreeDests(numPrinters, printers);
}
#else
// On GTK, we only ever show the CUPS name of printers, so we can use
// cupsGetNamedDest directly.
{
const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
printer = sCupsShim.cupsGetNamedDest(CUPS_HTTP_DEFAULT, printerName.get(),
nullptr);
printer = CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, printerName.get(),
nullptr);
}
#endif
@ -157,12 +163,12 @@ Maybe<PrinterInfo> nsPrinterListCUPS::PrinterByName(
Maybe<PrinterInfo> nsPrinterListCUPS::PrinterBySystemName(
nsString aPrinterName) const {
Maybe<PrinterInfo> rv;
if (!sCupsShim.EnsureInitialized()) {
if (!CupsShim().InitOkay()) {
return rv;
}
const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
if (cups_dest_t* const printer = sCupsShim.cupsGetNamedDest(
if (cups_dest_t* const printer = CupsShim().cupsGetNamedDest(
CUPS_HTTP_DEFAULT, printerName.get(), nullptr)) {
rv.emplace(PrinterInfo{std::move(aPrinterName), printer});
}
@ -172,14 +178,14 @@ Maybe<PrinterInfo> nsPrinterListCUPS::PrinterBySystemName(
nsresult nsPrinterListCUPS::SystemDefaultPrinterName(nsAString& aName) const {
aName.Truncate();
if (!sCupsShim.EnsureInitialized()) {
if (!CupsShim().InitOkay()) {
return NS_ERROR_FAILURE;
}
// Passing in nullptr for the name will return the default, if any.
cups_dest_t* dest =
sCupsShim.cupsGetNamedDest(CUPS_HTTP_DEFAULT, /* name */ nullptr,
/* instance */ nullptr);
CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, /* name */ nullptr,
/* instance */ nullptr);
if (!dest) {
return NS_OK;
}
@ -189,6 +195,6 @@ nsresult nsPrinterListCUPS::SystemDefaultPrinterName(nsAString& aName) const {
CopyUTF8toUTF16(mozilla::MakeStringSpan(dest->name), aName);
}
sCupsShim.cupsFreeDests(1, dest);
CupsShim().cupsFreeDests(1, dest);
return NS_OK;
}