Skip to content

Commit

Permalink
Bug 1337062 - Transfer initial gfxVars over command line - r=blassey
Browse files Browse the repository at this point in the history
When a subprocess is launched, gfxVars updates (for non-default values) are
serialized and passed on the command line, up to a limit of 1023 characters,
and ensuring it should not overflow the command line size.

When the child starts, the command line parameter is given to gfxVars, so the
updates can be used during gfxVars::Initialize(), instead of doing a sync
request to the parent.

In case the updates are not sent, or in the unlikely case the child cannot
parse them, we fallback to the sync request -- The former case should be rare
enough that a slow sync request is acceptable: It should only happen if D3D
block-list is *modified* (most people would either use the default, or just
overwrite these prefs with short strings.)

MozReview-Commit-ID: 6MoJC0fe59Q

--HG--
extra : rebase_source : cdc2e451783160c579b8fc84050e8457c600523e
  • Loading branch information
squelart committed Mar 28, 2017
1 parent 04137c0 commit 9c16b0c
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 7 deletions.
29 changes: 29 additions & 0 deletions dom/ipc/ContentParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,35 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
extraArgs.push_back("-stringPrefs");
extraArgs.push_back(stringPrefs.get());

char gfxBuf[1024];
nsFixedCString gfxVarsUpdates(gfxBuf, 1024, 0);
if (gfxVars::SerializeNonDefaultVarUpdates(gfxVarsUpdates, 1023)) {
// Don't add gfxVarsUpdates if they risk taking too much command line space.
const size_t maxArg =
#ifdef XP_WIN
8191;
#else
size_t(sysconf(_SC_ARG_MAX));
#endif
size_t extraArgsLength = 0;
for (const std::string& arg : extraArgs) {
extraArgsLength += arg.size() + 1;
}
if (extraArgsLength + size_t(gfxVarsUpdates.Length()) + 1024 < maxArg) {
extraArgs.push_back("-gfxVars");
if (gfxVarsUpdates.IsEmpty()) {
// Don't pass an empty string.
extraArgs.push_back("0");
} else {
extraArgs.push_back(gfxVarsUpdates.get());
}

// Since we have sent all gfxVarsUpdates known so far, we can start
// listening for updates.
gfxVars::AddReceiver(this);
}
}

if (gSafeMode) {
extraArgs.push_back("-safeMode");
}
Expand Down
12 changes: 10 additions & 2 deletions dom/ipc/ContentProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "nsDirectoryServiceDefs.h"
#endif

#include "mozilla/gfx/gfxVars.h"

using mozilla::ipc::IOThreadChild;

namespace mozilla {
Expand Down Expand Up @@ -203,8 +205,14 @@ ContentProcess::Init(int aArgc, char* aArgv[])
}
SET_PREF_PHASE(END_INIT_PREFS);
foundStringPrefs = true;
}
else if (!strcmp(aArgv[idx], "-safeMode")) {
} else if (!strcmp(aArgv[idx], "-gfxVars")) {
SET_PREF_PHASE(BEGIN_INIT_PREFS);
char* str = aArgv[idx + 1];
if (str[0] != '0' || str[1] != '\0') {
gfxVars::GotSerializedInitialVarUpdates(aArgv[idx + 1]);
}
SET_PREF_PHASE(END_INIT_PREFS);
} else if (!strcmp(aArgv[idx], "-safeMode")) {
gSafeMode = true;
}

Expand Down
193 changes: 188 additions & 5 deletions gfx/config/gfxVars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
#include "gfxVars.h"
#include "gfxVarReceiver.h"
#include "mozilla/dom/ContentChild.h"
#include "nsPrintfCString.h"


namespace mozilla {
namespace gfx {

StaticAutoPtr<gfxVars> gfxVars::sInstance;
StaticAutoPtr<nsTArray<gfxVars::VarBase*>> gfxVars::sVarList;
const char* gfxVars::sSerializedInitialVarUpdates = nullptr;

void
/* static */ void
gfxVars::Initialize()
{
if (sInstance) {
Expand All @@ -30,10 +33,13 @@ gfxVars::Initialize()
// init. Note the GPU process is not handled here - it cannot send sync
// messages, so instead the initial data is pushed down.
if (XRE_IsContentProcess()) {
InfallibleTArray<GfxVarUpdate> vars;
dom::ContentChild::GetSingleton()->SendGetGfxVars(&vars);
for (const auto& var : vars) {
ApplyUpdate(var);
if (!ApplySerializedVarUpdates(sSerializedInitialVarUpdates)) {
// No initial updates, or could not apply them -> Try sync retrieval.
InfallibleTArray<GfxVarUpdate> vars;
dom::ContentChild::GetSingleton()->SendGetGfxVars(&vars);
for (const auto& var : vars) {
ApplyUpdate(var);
}
}
}
}
Expand Down Expand Up @@ -101,6 +107,183 @@ gfxVars::FetchNonDefaultVars()
return updates;
}

/* static */ bool
gfxVars::SerializeNonDefaultVarUpdates(nsACString& aUpdates, size_t aMax)
{
MOZ_ASSERT(NS_IsMainThread());

if (!sVarList) {
return false;
}

for (size_t i = 0; i < sVarList->Length(); i++) {
VarBase* var = sVarList->ElementAt(i);
if (var->HasDefaultValue()) {
continue;
}

GfxVarValue value;
var->GetValue(&value);

switch (value.type()) {
case mozilla::gfx::GfxVarValue::TBackendType: {
nsPrintfCString t("T%zu:%d|", i, int(value.get_BackendType()));
if (aUpdates.Length() + t.Length() > aMax) {
return false;
}
aUpdates.Append(t);
}
break;
case mozilla::gfx::GfxVarValue::Tbool: {
nsPrintfCString b("B%zu:%d|",
i, int(value.get_bool()));
if (aUpdates.Length() + b.Length() > aMax) {
return false;
}
aUpdates.Append(b);
}
break;
case mozilla::gfx::GfxVarValue::TgfxImageFormat: {
nsPrintfCString f("F%zu:%d|", i, int(value.get_gfxImageFormat()));
if (aUpdates.Length() + f.Length() > aMax) {
return false;
}
aUpdates.Append(f);
}
break;
case mozilla::gfx::GfxVarValue::TIntSize: {
nsPrintfCString z("Z%zu:%dx%d|",
i,
int(value.get_IntSize().width),
int(value.get_IntSize().height));
if (aUpdates.Length() + z.Length() > aMax) {
return false;
}
aUpdates.Append(z);
}
break;
case mozilla::gfx::GfxVarValue::TnsCString: {
nsPrintfCString s("S%zu:%u;%s|",
i,
value.get_nsCString().Length(),
value.get_nsCString().get());
if (aUpdates.Length() + s.Length() > aMax) {
return false;
}
aUpdates.Append(s);
}
break;
default:
MOZ_ASSERT(false);
return false;
}
}

return true;
}

/* static */ void
gfxVars::GotSerializedInitialVarUpdates(const char* aUpdates)
{
sSerializedInitialVarUpdates = aUpdates;
}

/* static */ bool
gfxVars::ApplySerializedVarUpdates(const char* aUpdates)
{
if (!aUpdates) {
return false;
}

for (const char* p = aUpdates; *p;) {
switch (*p++) {
case 'T': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t type = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(BackendType(type))));
}
break;
case 'B': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t b = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(bool(b))));
}
break;
case 'F': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t format = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(gfxImageFormat(format))));
}
break;
case 'Z': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t width = strtol(p, const_cast<char**>(&p), 10);
if (*p != 'x') {
return false;
}
p++;
int32_t height = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(IntSize(width, height))));
}
break;
case 'S': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t length = strtol(p, const_cast<char**>(&p), 10);
if (*p != ';') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(nsCString(p, length))));
p += length;
if (*p++ != '|') {
return false;
}
}
break;
default:
return false;
}
}

return true;
}

gfxVars::VarBase::VarBase()
{
mIndex = gfxVars::sVarList->Length();
Expand Down
9 changes: 9 additions & 0 deletions gfx/config/gfxVars.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ class gfxVars final

// Return a list of updates for all variables with non-default values.
static nsTArray<GfxVarUpdate> FetchNonDefaultVars();
// Fill aUpdates with serialized updates for all variables with non-default
// values. Return true if ok, false if length>aMax or other issue.
static bool SerializeNonDefaultVarUpdates(nsACString& aUpdates, size_t aMax);
// Inform gfxVars that some initial updates are available, to be used from
// a child's Initialize(), instead of doing a sync request to the parent.
static void GotSerializedInitialVarUpdates(const char* aUpdates);

public:
// Each variable must expose Set and Get methods for IPDL.
Expand All @@ -86,6 +92,7 @@ class gfxVars final
private:
static StaticAutoPtr<gfxVars> sInstance;
static StaticAutoPtr<nsTArray<VarBase*>> sVarList;
static const char* sSerializedInitialVarUpdates;

template <typename T, T Default()>
class VarImpl final : public VarBase
Expand Down Expand Up @@ -141,6 +148,8 @@ public: \
private:
gfxVars();

static bool ApplySerializedVarUpdates(const char* aUpdates);

void NotifyReceivers(VarBase* aVar);

private:
Expand Down

0 comments on commit 9c16b0c

Please sign in to comment.