Merge mozilla-central to autoland. a=merge

--HG--
extra : rebase_source : 29933c2409d7ab8c51343cf463aa4303e569c530
This commit is contained in:
dvarga 2018-07-28 01:40:41 +03:00
Родитель befb9a51e6 d8ac8507c9
Коммит 0201242956
29 изменённых файлов: 308 добавлений и 399 удалений

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

@ -13,6 +13,7 @@ import shutil
import sys
from automation import Automation
from mozdevice import ADBTimeoutError
from mozlog import get_default_logger
from mozscreenshot import dump_screen
import mozcrash
@ -294,6 +295,8 @@ class RemoteAutomation(Automation):
try:
newLogContent = self.device.get_file(
self.proc, offset=self.stdoutlen)
except ADBTimeoutError:
raise
except Exception:
return False
if not newLogContent:
@ -344,6 +347,8 @@ class RemoteAutomation(Automation):
self.counts['fail'] += val
elif "Todo:" in line:
self.counts['todo'] += val
except ADBTimeoutError:
raise
except Exception:
pass
@ -412,12 +417,16 @@ class RemoteAutomation(Automation):
# Trigger an ANR report with "kill -3" (SIGQUIT)
try:
self.device.pkill(self.procName, sig=3, attempts=1)
except ADBTimeoutError:
raise
except: # NOQA: E722
pass
time.sleep(3)
# Trigger a breakpad dump with "kill -6" (SIGABRT)
try:
self.device.pkill(self.procName, sig=6, attempts=1)
except ADBTimeoutError:
raise
except: # NOQA: E722
pass
# Wait for process to end
@ -431,6 +440,8 @@ class RemoteAutomation(Automation):
retries += 1
try:
self.device.pkill(self.procName, sig=9, attempts=1)
except ADBTimeoutError:
raise
except: # NOQA: E722
print("%s still alive after SIGKILL!" % self.procName)
if self.device.process_exist(self.procName):

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

@ -59,7 +59,6 @@ struct AudioIpcInitParams {
int mServerConnection;
size_t mPoolSize;
size_t mStackSize;
void (*mThreadCreateCallback)(const char*);
};
// These functions are provided by audioipc-server crate
@ -431,9 +430,6 @@ cubeb* GetCubebContextUnlocked()
initParams.mPoolSize = sAudioIPCPoolSize;
initParams.mStackSize = sAudioIPCStackSize;
initParams.mServerConnection = sIPCConnection->ClonePlatformHandle().release();
initParams.mThreadCreateCallback = [](const char* aName) {
PROFILER_REGISTER_THREAD(aName);
};
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_POOL_SIZE, (int) initParams.mPoolSize));
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_STACK_SIZE, (int) initParams.mStackSize));

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

@ -1,4 +1,4 @@
52849
52853
0/nm
0th/pt
1/n1
@ -22179,6 +22179,7 @@ dc
dd/SDG
dded/K
dding/K
de
deacon/MS
deaconess/MS
dead/XTMNRY
@ -25795,6 +25796,7 @@ factional
factionalism/M
factious
factitious
facto
factoid/SM
factor's
factor/ASDG
@ -42052,6 +42054,7 @@ reasoner/M
reasoning/M
reassemble/DSG
reassuring/Y
rebar/S
rebate/M
rebel/MS
rebellion/MS
@ -44263,6 +44266,7 @@ segfault/S
segment/GSMD
segmentation/M
segmented/U
segregable
segregate/CDSGN
segregated/U
segregation/CM

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

@ -26,8 +26,6 @@
#include <pthread_np.h>
#endif
#include "nsThreadUtils.h"
#if defined(OS_MACOSX)
namespace base {
void InitThreading();
@ -35,10 +33,6 @@ void InitThreading();
#endif
static void* ThreadFunc(void* closure) {
// Create a nsThread wrapper for the current platform thread, and register it
// with the thread manager.
(void) NS_GetCurrentThread();
PlatformThread::Delegate* delegate =
static_cast<PlatformThread::Delegate*>(closure);
delegate->ThreadMain();
@ -98,10 +92,21 @@ void PlatformThread::SetName(const char* name) {
if (PlatformThread::CurrentId() == getpid())
return;
// Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
// also sets the thread name on the PRThread wrapper, and allows us to
// retrieve it using PR_GetThreadName.
NS_SetCurrentThreadName(name);
// http://0pointer.de/blog/projects/name-your-threads.html
// Set the name for the LWP (which gets truncated to 15 characters).
// Note that glibc also has a 'pthread_setname_np' api, but it may not be
// available everywhere and it's only benefit over using prctl directly is
// that it can set the name of threads other than the current thread.
#if defined(OS_LINUX)
prctl(PR_SET_NAME, reinterpret_cast<uintptr_t>(name), 0, 0, 0);
#elif defined(OS_NETBSD)
pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif defined(OS_BSD) && !defined(__GLIBC__)
pthread_set_name_np(pthread_self(), name);
#elif defined(OS_SOLARIS)
pthread_setname_np(pthread_self(), name);
#else
#endif
}
#endif // !OS_MACOSX
@ -124,9 +129,8 @@ bool CreateThread(size_t stack_size, bool joinable,
pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
}
if (stack_size == 0)
stack_size = nsIThreadManager::DEFAULT_STACK_SIZE;
pthread_attr_setstacksize(&attributes, stack_size);
if (stack_size > 0)
pthread_attr_setstacksize(&attributes, stack_size);
success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);

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

@ -9,8 +9,6 @@
#include "base/logging.h"
#include "base/win_util.h"
#include "nsThreadUtils.h"
namespace {
// The information on how to set the thread name comes from
@ -25,10 +23,6 @@ typedef struct tagTHREADNAME_INFO {
} THREADNAME_INFO;
DWORD __stdcall ThreadFunc(void* closure) {
// Create a nsThread wrapper for the current platform thread, and register it
// with the thread manager.
(void) NS_GetCurrentThread();
PlatformThread::Delegate* delegate =
static_cast<PlatformThread::Delegate*>(closure);
delegate->ThreadMain();
@ -54,10 +48,24 @@ void PlatformThread::Sleep(int duration_ms) {
// static
void PlatformThread::SetName(const char* name) {
// Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
// also sets the thread name on the PRThread wrapper, and allows us to
// retrieve it using PR_GetThreadName.
NS_SetCurrentThreadName(name);
#ifdef HAVE_SEH_EXCEPTIONS
// The debugger needs to be around to catch the name in the exception. If
// there isn't a debugger, we are just needlessly throwing an exception.
if (!::IsDebuggerPresent())
return;
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = CurrentId();
info.dwFlags = 0;
MOZ_SEH_TRY {
RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
reinterpret_cast<DWORD_PTR*>(&info));
} MOZ_SEH_EXCEPT(EXCEPTION_CONTINUE_EXECUTION) {
}
#endif
}
// static

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

@ -113,6 +113,14 @@ class SharedMemory {
return ShareToProcessCommon(target_pid, new_handle, true);
}
#ifdef OS_POSIX
// If named POSIX shm is being used, append the prefix (including
// the leading '/') that would be used by a process with the given
// pid to the given string and return true. If not, return false.
// (This is public so that the Linux sandboxing code can use it.)
static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
#endif
private:
bool ShareToProcessCommon(ProcessId target_pid,
SharedMemoryHandle* new_handle,

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

@ -12,11 +12,15 @@
#include <sys/stat.h>
#include <unistd.h>
#include "base/file_util.h"
#ifdef ANDROID
#include <linux/ashmem.h>
#endif
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Atomics.h"
#include "prenv.h"
namespace base {
@ -49,20 +53,28 @@ SharedMemoryHandle SharedMemory::NULLHandle() {
return SharedMemoryHandle();
}
namespace {
// A class to handle auto-closing of FILE*'s.
class ScopedFILEClose {
public:
inline void operator()(FILE* x) const {
if (x) {
fclose(x);
}
// static
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid)
{
#if defined(ANDROID) || defined(SHM_ANON)
return false;
#else
*str += '/';
#ifdef OS_LINUX
// The Snap package environment doesn't provide a private /dev/shm
// (it's used for communication with services like PulseAudio);
// instead AppArmor is used to restrict access to it. Anything with
// this prefix is allowed:
static const char* const kSnap = PR_GetEnv("SNAP_NAME");
if (kSnap) {
StringAppendF(str, "snap.%s.", kSnap);
}
};
typedef mozilla::UniquePtr<FILE, ScopedFILEClose> ScopedFILE;
#endif // OS_LINUX
// Hopefully the "implementation defined" name length limit is long
// enough for this.
StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
return true;
#endif // !ANDROID && !SHM_ANON
}
bool SharedMemory::Create(size_t size) {
@ -71,37 +83,62 @@ bool SharedMemory::Create(size_t size) {
DCHECK(size > 0);
DCHECK(mapped_file_ == -1);
ScopedFILE file_closer;
FILE *fp;
int fd;
bool needs_truncate = true;
FilePath path;
fp = file_util::CreateAndOpenTemporaryShmemFile(&path);
// Deleting the file prevents anyone else from mapping it in
// (making it private), and prevents the need for cleanup (once
// the last fd is closed, it is truly freed).
file_util::Delete(path);
if (fp == NULL)
#ifdef ANDROID
// Android has its own shared memory facility:
fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
if (fd < 0) {
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
return false;
file_closer.reset(fp); // close when we go out of scope
// Set the file size.
//
// According to POSIX, (f)truncate can be used to extend files;
// previously this required the XSI option but as of the 2008
// edition it's required for everything. (Linux documents that this
// may fail on non-"native" filesystems like FAT, but /dev/shm
// should always be tmpfs.)
if (ftruncate(fileno(fp), size) != 0)
}
if (ioctl(fd, ASHMEM_SET_SIZE, size) != 0) {
CHROMIUM_LOG(WARNING) << "failed to set shm size: " << strerror(errno);
close(fd);
return false;
// This probably isn't needed.
if (fseeko(fp, size, SEEK_SET) != 0)
}
needs_truncate = false;
#elif defined(SHM_ANON)
// FreeBSD (or any other Unix that might decide to implement this
// nice, simple API):
fd = shm_open(SHM_ANON, O_RDWR, 0600);
#else
// Generic Unix: shm_open + shm_unlink
do {
// The names don't need to be unique, but it saves time if they
// usually are.
static mozilla::Atomic<size_t> sNameCounter;
std::string name;
CHECK(AppendPosixShmPrefix(&name, getpid()));
StringAppendF(&name, "%zu", sNameCounter++);
// O_EXCL means the names being predictable shouldn't be a problem.
fd = HANDLE_EINTR(shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600));
if (fd >= 0) {
if (shm_unlink(name.c_str()) != 0) {
// This shouldn't happen, but if it does: assume the file is
// in fact leaked, and bail out now while it's still 0-length.
DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
return false;
}
}
} while (fd < 0 && errno == EEXIST);
#endif
if (fd < 0) {
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
return false;
}
mapped_file_ = dup(fileno(fp));
DCHECK(mapped_file_ >= 0);
if (needs_truncate) {
if (HANDLE_EINTR(ftruncate(fd, static_cast<off_t>(size))) != 0) {
CHROMIUM_LOG(WARNING) << "failed to set shm size: " << strerror(errno);
close(fd);
return false;
}
}
mapped_file_ = fd;
max_size_ = size;
return true;
}

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

@ -381,7 +381,7 @@ def find_tests(substring=None):
def run_test_remote(test, device, prefix, options):
from mozdevice import ADBDevice, ADBProcessError
from mozdevice import ADBDevice, ADBProcessError, ADBTimeoutError
if options.test_reflect_stringify:
raise ValueError("can't run Reflect.stringify tests remotely")
@ -405,6 +405,8 @@ def run_test_remote(test, device, prefix, options):
cwd=options.remote_test_root,
timeout=int(options.timeout))
returncode = 0
except ADBTimeoutError:
raise
except ADBProcessError as e:
out = e.adb_process.stdout
print("exception output: %s" % str(out))

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

@ -943,12 +943,7 @@ js::CurrentThreadIsParseThread()
}
#endif
// We want our default stack size limit to be approximately 2MB, to be safe, but
// expect most threads to use much less. On Linux, however, requesting a stack
// of 2MB or larger risks the kernel allocating an entire 2MB huge page for it
// on first access, which we do not want. To avoid this possibility, we subtract
// 2 standard VM page sizes from our default.
static const uint32_t kDefaultHelperStackSize = 2048 * 1024 - 2 * 4096;
static const uint32_t kDefaultHelperStackSize = 2048 * 1024;
static const uint32_t kDefaultHelperStackQuota = 1800 * 1024;
// TSan enforces a minimum stack size that's just slightly larger than our

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

@ -79,10 +79,6 @@ using namespace xpc;
using namespace JS;
using mozilla::dom::AutoEntryScript;
// The watchdog thread loop is pretty trivial, and should not require much stack
// space to do its job. So only give it 32KiB.
static constexpr size_t kWatchdogStackSize = 32 * 1024;
static void WatchdogMain(void* arg);
class Watchdog;
class WatchdogManager;
@ -147,7 +143,7 @@ class Watchdog
// join it on shutdown.
mThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, kWatchdogStackSize);
PR_JOINABLE_THREAD, 0);
if (!mThread)
MOZ_CRASH("PR_CreateThread failed!");
@ -476,8 +472,6 @@ static void
WatchdogMain(void* arg)
{
AUTO_PROFILER_REGISTER_THREAD("JS Watchdog");
// Create an nsThread wrapper for the thread and register it with the thread manager.
Unused << NS_GetCurrentThread();
NS_SetCurrentThreadName("JS Watchdog");
Watchdog* self = static_cast<Watchdog*>(arg);

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

@ -13,7 +13,7 @@ import traceback
import urllib2
from contextlib import closing
from mozdevice import ADBAndroid
from mozdevice import ADBAndroid, ADBTimeoutError
import mozinfo
from automation import Automation
from remoteautomation import RemoteAutomation, fennecLogcatFilters
@ -349,6 +349,8 @@ class RemoteReftest(RefTest):
else:
print " %s: %s" % (category, devinfo[category])
print "Test root: %s" % self.device.test_root
except ADBTimeoutError:
raise
except Exception as e:
print "WARNING: Error getting device information: %s" % str(e)

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

@ -20,7 +20,6 @@ use std::os::raw::c_void;
use std::os::unix::io::FromRawFd;
use std::os::unix::net;
use std::sync::mpsc;
use std::thread;
use stream;
use tokio_core::reactor::{Handle, Remote};
use tokio_uds::UnixStream;
@ -100,25 +99,9 @@ impl ContextOps for ClientContext {
let (tx_rpc, rx_rpc) = mpsc::channel();
let params = CPUPOOL_INIT_PARAMS.with(|p| {
p.replace(None).unwrap()
});
let thread_create_callback = params.thread_create_callback;
let register_thread = move || {
if let Some(func) = thread_create_callback {
let thr = thread::current();
let name = CString::new(thr.name().unwrap()).unwrap();
func(name.as_ptr());
}
};
let core = t!(core::spawn_thread("AudioIPC Client RPC", move || {
let handle = core::handle();
register_thread();
open_server_stream()
.ok()
.and_then(|stream| UnixStream::from_stream(stream, &handle).ok())
@ -133,12 +116,14 @@ impl ContextOps for ClientContext {
let rpc = t!(rx_rpc.recv());
let cpupool = futures_cpupool::Builder::new()
let cpupool = CPUPOOL_INIT_PARAMS.with(|p| {
let params = p.replace(None).unwrap();
futures_cpupool::Builder::new()
.name_prefix("AudioIPC")
.after_start(register_thread)
.pool_size(params.pool_size)
.stack_size(params.stack_size)
.create();
.create()
});
let ctx = Box::new(ClientContext {
_ops: &CLIENT_OPS as *const _,

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

@ -37,14 +37,12 @@ pub struct AudioIpcInitParams {
pub server_connection: c_int,
pub pool_size: usize,
pub stack_size: usize,
pub thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
}
#[derive(Clone, Copy, Debug)]
struct CpuPoolInitParams {
pub pool_size: usize,
pub stack_size: usize,
pub thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
}
impl CpuPoolInitParams {
@ -52,7 +50,6 @@ impl CpuPoolInitParams {
CpuPoolInitParams {
pool_size: params.pool_size,
stack_size: params.stack_size,
thread_create_callback: params.thread_create_callback,
}
}
}

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

@ -207,6 +207,7 @@
# Windows, clang-cl build
[ 'clang_cl == 1', {
'cflags_mozilla': [
'-Xclang',
'-Wall',
'-Wno-parentheses',
'-Wno-strict-prototypes',

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

@ -204,6 +204,7 @@
# Windows, clang-cl build
[ 'clang_cl == 1', {
'cflags_mozilla': [
'-Xclang',
'-Wall',
'-Wno-parentheses',
'-Wno-strict-prototypes',

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

@ -26,7 +26,6 @@ from .timeout import Timeouts
CHROME_ELEMENT_KEY = "chromeelement-9fc5-4b51-a3c8-01716eedeb04"
FRAME_KEY = "frame-075b-4da1-b6ba-e579c2d3230a"
LEGACY_ELEMENT_KEY = "ELEMENT"
WEB_ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
WINDOW_KEY = "window-fcc6-11e5-b4f8-330a88ab9d7f"
@ -34,8 +33,7 @@ WINDOW_KEY = "window-fcc6-11e5-b4f8-330a88ab9d7f"
class HTMLElement(object):
"""Represents a DOM Element."""
identifiers = (CHROME_ELEMENT_KEY, FRAME_KEY, WINDOW_KEY,
LEGACY_ELEMENT_KEY, WEB_ELEMENT_KEY)
identifiers = (CHROME_ELEMENT_KEY, FRAME_KEY, WINDOW_KEY, WEB_ELEMENT_KEY)
def __init__(self, marionette, id):
self.marionette = marionette
@ -187,8 +185,6 @@ class HTMLElement(object):
if isinstance(json, dict):
if WEB_ELEMENT_KEY in json:
return cls(marionette, json[WEB_ELEMENT_KEY])
elif LEGACY_ELEMENT_KEY in json:
return cls(marionette, json[LEGACY_ELEMENT_KEY])
elif CHROME_ELEMENT_KEY in json:
return cls(marionette, json[CHROME_ELEMENT_KEY])
elif FRAME_KEY in json:
@ -1611,7 +1607,7 @@ class Marionette(object):
wrapped[arg] = self._to_json(args[arg])
elif type(args) == HTMLElement:
wrapped = {WEB_ELEMENT_KEY: args.id,
LEGACY_ELEMENT_KEY: args.id}
CHROME_ELEMENT_KEY: args.id}
elif (isinstance(args, bool) or isinstance(args, basestring) or
isinstance(args, int) or isinstance(args, float) or args is None):
wrapped = args

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

@ -1443,7 +1443,6 @@ class WebElement {
for (let key of keys) {
switch (key) {
case ContentWebElement.Identifier:
case ContentWebElement.LegacyIdentifier:
return ContentWebElement.fromJSON(json);
case ContentWebWindow.Identifier:
@ -1502,8 +1501,7 @@ class WebElement {
/**
* Checks if <var>ref<var> is a {@link WebElement} reference,
* i.e. if it has {@link ContentWebElement.Identifier},
* {@link ContentWebElement.LegacyIdentifier}, or
* i.e. if it has {@link ContentWebElement.Identifier}, or
* {@link ChromeWebElement.Identifier} as properties.
*
* @param {Object.<string, string>} obj
@ -1517,7 +1515,6 @@ class WebElement {
}
if ((ContentWebElement.Identifier in obj) ||
(ContentWebElement.LegacyIdentifier in obj) ||
(ContentWebWindow.Identifier in obj) ||
(ContentWebFrame.Identifier in obj) ||
(ChromeWebElement.Identifier in obj)) {
@ -1545,26 +1542,22 @@ this.WebElement = WebElement;
*/
class ContentWebElement extends WebElement {
toJSON() {
return {
[ContentWebElement.Identifier]: this.uuid,
[ContentWebElement.LegacyIdentifier]: this.uuid,
};
return {[ContentWebElement.Identifier]: this.uuid};
}
static fromJSON(json) {
const {Identifier, LegacyIdentifier} = ContentWebElement;
const {Identifier} = ContentWebElement;
if (!(Identifier in json) && !(LegacyIdentifier in json)) {
if (!(Identifier in json)) {
throw new InvalidArgumentError(
pprint`Expected web element reference, got: ${json}`);
}
let uuid = json[Identifier] || json[LegacyIdentifier];
let uuid = json[Identifier];
return new ContentWebElement(uuid);
}
}
ContentWebElement.Identifier = "element-6066-11e4-a52e-4f735466cecf";
ContentWebElement.LegacyIdentifier = "ELEMENT";
this.ContentWebElement = ContentWebElement;
/**
@ -1574,10 +1567,7 @@ this.ContentWebElement = ContentWebElement;
*/
class ContentWebWindow extends WebElement {
toJSON() {
return {
[ContentWebWindow.Identifier]: this.uuid,
[ContentWebElement.LegacyIdentifier]: this.uuid,
};
return {[ContentWebWindow.Identifier]: this.uuid};
}
static fromJSON(json) {
@ -1599,10 +1589,7 @@ this.ContentWebWindow = ContentWebWindow;
*/
class ContentWebFrame extends WebElement {
toJSON() {
return {
[ContentWebFrame.Identifier]: this.uuid,
[ContentWebElement.LegacyIdentifier]: this.uuid,
};
return {[ContentWebFrame.Identifier]: this.uuid};
}
static fromJSON(json) {
@ -1623,10 +1610,7 @@ this.ContentWebFrame = ContentWebFrame;
*/
class ChromeWebElement extends WebElement {
toJSON() {
return {
[ChromeWebElement.Identifier]: this.uuid,
[ContentWebElement.LegacyIdentifier]: this.uuid,
};
return {[ChromeWebElement.Identifier]: this.uuid};
}
static fromJSON(json) {

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

@ -358,37 +358,15 @@ add_test(function test_WebElement_from() {
});
add_test(function test_WebElement_fromJSON_ContentWebElement() {
const {Identifier, LegacyIdentifier} = ContentWebElement;
const {Identifier} = ContentWebElement;
let refNew = {[Identifier]: "foo"};
let webElNew = WebElement.fromJSON(refNew);
ok(webElNew instanceof ContentWebElement);
equal(webElNew.uuid, "foo");
let refOld = {[LegacyIdentifier]: "foo"};
let webElOld = WebElement.fromJSON(refOld);
ok(webElOld instanceof ContentWebElement);
equal(webElOld.uuid, "foo");
ok(webElNew.is(webElOld));
ok(webElOld.is(webElNew));
let refBoth = {
[Identifier]: "foo",
[LegacyIdentifier]: "foo",
};
let webElBoth = WebElement.fromJSON(refBoth);
ok(webElBoth instanceof ContentWebElement);
equal(webElBoth.uuid, "foo");
ok(webElBoth.is(webElNew));
ok(webElBoth.is(webElOld));
ok(webElNew.is(webElBoth));
ok(webElOld.is(webElBoth));
let ref = {[Identifier]: "foo"};
let webEl = WebElement.fromJSON(ref);
ok(webEl instanceof ContentWebElement);
equal(webEl.uuid, "foo");
let identifierPrecedence = {
[Identifier]: "identifier-uuid",
[LegacyIdentifier]: "legacyidentifier-uuid",
};
let precedenceEl = WebElement.fromJSON(identifierPrecedence);
ok(precedenceEl instanceof ContentWebElement);
@ -450,7 +428,6 @@ add_test(function test_WebElement_isReference() {
}
ok(WebElement.isReference({[ContentWebElement.Identifier]: "foo"}));
ok(WebElement.isReference({[ContentWebElement.LegacyIdentifier]: "foo"}));
ok(WebElement.isReference({[ContentWebWindow.Identifier]: "foo"}));
ok(WebElement.isReference({[ContentWebFrame.Identifier]: "foo"}));
ok(WebElement.isReference({[ChromeWebElement.Identifier]: "foo"}));
@ -464,37 +441,23 @@ add_test(function test_WebElement_generateUUID() {
});
add_test(function test_ContentWebElement_toJSON() {
const {Identifier, LegacyIdentifier} = ContentWebElement;
const {Identifier} = ContentWebElement;
let el = new ContentWebElement("foo");
let json = el.toJSON();
ok(Identifier in json);
ok(LegacyIdentifier in json);
equal(json[Identifier], "foo");
equal(json[LegacyIdentifier], "foo");
run_next_test();
});
add_test(function test_ContentWebElement_fromJSON() {
const {Identifier, LegacyIdentifier} = ContentWebElement;
const {Identifier} = ContentWebElement;
let newEl = ContentWebElement.fromJSON({[Identifier]: "foo"});
ok(newEl instanceof ContentWebElement);
equal(newEl.uuid, "foo");
let oldEl = ContentWebElement.fromJSON({[LegacyIdentifier]: "foo"});
ok(oldEl instanceof ContentWebElement);
equal(oldEl.uuid, "foo");
let bothRef = {
[Identifier]: "identifier-uuid",
[LegacyIdentifier]: "legacyidentifier-foo",
};
let bothEl = ContentWebElement.fromJSON(bothRef);
ok(bothEl instanceof ContentWebElement);
equal(bothEl.uuid, "identifier-uuid");
let el = ContentWebElement.fromJSON({[Identifier]: "foo"});
ok(el instanceof ContentWebElement);
equal(el.uuid, "foo");
Assert.throws(() => ContentWebElement.fromJSON({}), InvalidArgumentError);

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

@ -22,7 +22,7 @@ from mochitest_options import MochitestArgumentParser
from manifestparser import TestManifest
from manifestparser.filters import chunk_by_slice
from mozdevice import ADBAndroid
from mozdevice import ADBAndroid, ADBTimeoutError
import mozfile
import mozinfo
@ -341,6 +341,8 @@ class RobocopTestRunner(MochitestDesktop):
else:
self.log.info(" %s: %s" % (category, devinfo[category]))
self.log.info("Test root: %s" % self.device.test_root)
except ADBTimeoutError:
raise
except Exception as e:
self.log.warning("Error getting device information: %s" % str(e))

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

@ -2813,10 +2813,13 @@ toolbar#nav-bar {
except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n")
status = -1
except Exception:
except Exception as e:
traceback.print_exc()
self.log.error(
"Automation Error: Received unexpected exception while running application\n")
if 'ADBTimeoutError' in repr(e):
self.log.info("runtests.py | Device disconnected. Aborting test.\n")
raise
status = 1
finally:
self.stopServers()

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

@ -17,7 +17,7 @@ from remoteautomation import RemoteAutomation, fennecLogcatFilters
from runtests import MochitestDesktop, MessageLogger
from mochitest_options import MochitestArgumentParser
from mozdevice import ADBAndroid
from mozdevice import ADBAndroid, ADBTimeoutError
import mozinfo
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
@ -283,6 +283,8 @@ class MochiRemote(MochitestDesktop):
else:
self.log.info(" %s: %s" % (category, devinfo[category]))
self.log.info("Test root: %s" % self.device.test_root)
except ADBTimeoutError:
raise
except Exception as e:
self.log.warning("Error getting device information: %s" % str(e))
@ -344,21 +346,26 @@ def run_test_harness(parser, options):
mochitest.printDeviceInfo()
try:
device_exception = False
if options.verify:
retVal = mochitest.verifyTests(options)
else:
retVal = mochitest.runTests(options)
except Exception:
except Exception as e:
mochitest.log.error("Automation Error: Exception caught while running tests")
traceback.print_exc()
try:
mochitest.cleanup(options)
except Exception:
# device error cleaning up... oh well!
traceback.print_exc()
if isinstance(e, ADBTimeoutError):
mochitest.log.info("Device disconnected. Will not run mochitest.cleanup().")
device_exception = True
else:
try:
mochitest.cleanup(options)
except Exception:
# device error cleaning up... oh well!
traceback.print_exc()
retVal = 1
if options.log_mach is None and not options.verify:
if not device_exception and options.log_mach is None and not options.verify:
mochitest.printDeviceInfo(printLogcat=True)
mochitest.message_logger.finish()

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

@ -14,7 +14,7 @@ import mozfile
import mozinfo
import mozlog
import posixpath
from mozdevice import ADBAndroid, ADBProcessError
from mozdevice import ADBAndroid, ADBProcessError, ADBTimeoutError
try:
from mozbuild.base import MozbuildObject
@ -139,6 +139,8 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
cwd=self.remote_home_dir,
timeout=test_timeout)
returncode = 0
except ADBTimeoutError:
raise
except ADBProcessError as e:
output = e.adb_process.stdout
returncode = e.adb_process.exitcode

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

@ -16,7 +16,7 @@ import runxpcshelltests as xpcshell
import tempfile
from zipfile import ZipFile
from mozdevice import ADBAndroid, ADBDevice
from mozdevice import ADBAndroid, ADBDevice, ADBTimeoutError
import mozfile
import mozinfo
from mozlog import commandline
@ -156,6 +156,8 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
adb_process = self.device.shell(cmd, timeout=timeout+10, root=True)
output_file = adb_process.stdout_file
self.shellReturnCode = adb_process.exitcode
except ADBTimeoutError:
raise
except Exception as e:
if self.timedout:
# If the test timed out, there is a good chance the shell
@ -214,6 +216,8 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
def removeDir(self, dirname):
try:
self.device.rm(dirname, recursive=True, root=True)
except ADBTimeoutError:
raise
except Exception as e:
self.log.warning(str(e))

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

@ -268,8 +268,7 @@ BackgroundHangManager::BackgroundHangManager()
mHangMonitorThread = PR_CreateThread(
PR_USER_THREAD, MonitorThread, this,
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
nsIThreadManager::DEFAULT_STACK_SIZE);
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
MOZ_ASSERT(mHangMonitorThread, "Failed to create BHR monitor thread");

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

@ -3298,11 +3298,6 @@ profiler_register_thread(const char* aName, void* aGuessStackTop)
MOZ_ASSERT_IF(NS_IsMainThread(), Scheduler::IsCooperativeThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
// Make sure we have a nsThread wrapper for the current thread, and that NSPR
// knows its name.
(void) NS_GetCurrentThread();
NS_SetCurrentThreadName(aName);
PSAutoLock lock(gPSMutex);
void* stackTop = GetStackTop(aGuessStackTop);

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

@ -405,13 +405,6 @@ nsThread::ThreadList()
return sList;
}
/* static */ void
nsThread::ClearThreadList()
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
while (ThreadList().popFirst()) {}
}
/* static */ nsThreadEnumerator
nsThread::Enumerate()
{
@ -427,6 +420,7 @@ nsThread::ThreadFunc(void* aArg)
nsThread* self = initData->thread; // strong reference
self->mThread = PR_GetCurrentThread();
self->mThreadId = uint32_t(PlatformThread::CurrentId());
self->mVirtualThread = GetCurrentVirtualThread();
self->mEventTarget->SetCurrentThread();
SetupCurrentThreadForChaosMode();
@ -435,7 +429,71 @@ nsThread::ThreadFunc(void* aArg)
NS_SetCurrentThreadName(initData->name.BeginReading());
}
self->InitCommon();
{
#if defined(XP_LINUX)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr);
size_t stackSize;
pthread_attr_getstack(&attr, &self->mStackBase, &stackSize);
// Glibc prior to 2.27 reports the stack size and base including the guard
// region, so we need to compensate for it to get accurate accounting.
// Also, this behavior difference isn't guarded by a versioned symbol, so we
// actually need to check the runtime glibc version, not the version we were
// compiled against.
static bool sAdjustForGuardSize = ({
#ifdef __GLIBC__
unsigned major, minor;
sscanf(gnu_get_libc_version(), "%u.%u", &major, &minor) < 2 ||
major < 2 || (major == 2 && minor < 27);
#else
false;
#endif
});
if (sAdjustForGuardSize) {
size_t guardSize;
pthread_attr_getguardsize(&attr, &guardSize);
// Note: This assumes that the stack grows down, as is the case on all of
// our tier 1 platforms. On platforms where the stack grows up, the
// mStackBase adjustment is unnecessary, but doesn't cause any harm other
// than under-counting stack memory usage by one page.
self->mStackBase = reinterpret_cast<char*>(self->mStackBase) + guardSize;
stackSize -= guardSize;
}
self->mStackSize = stackSize;
// This is a bit of a hack.
//
// We really do want the NOHUGEPAGE flag on our thread stacks, since we
// don't expect any of them to need anywhere near 2MB of space. But setting
// it here is too late to have an effect, since the first stack page has
// already been faulted in existence, and NSPR doesn't give us a way to set
// it beforehand.
//
// What this does get us, however, is a different set of VM flags on our
// thread stacks compared to normal heap memory. Which makes the Linux
// kernel report them as separate regions, even when they are adjacent to
// heap memory. This allows us to accurately track the actual memory
// consumption of our allocated stacks.
madvise(self->mStackBase, stackSize, MADV_NOHUGEPAGE);
pthread_attr_destroy(&attr);
#elif defined(XP_WIN)
static const DynamicallyLinkedFunctionPtr<GetCurrentThreadStackLimitsFn>
sGetStackLimits(L"kernel32.dll", "GetCurrentThreadStackLimits");
if (sGetStackLimits) {
ULONG_PTR stackBottom, stackTop;
sGetStackLimits(&stackBottom, &stackTop);
self->mStackBase = reinterpret_cast<void*>(stackBottom);
self->mStackSize = stackTop - stackBottom;
}
#endif
}
// Inform the ThreadManager
nsThreadManager::get().RegisterCurrentThread(*self);
@ -516,81 +574,6 @@ nsThread::ThreadFunc(void* aArg)
NS_RELEASE(self);
}
void
nsThread::InitCommon()
{
mThreadId = uint32_t(PlatformThread::CurrentId());
{
#if defined(XP_LINUX)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr);
size_t stackSize;
pthread_attr_getstack(&attr, &mStackBase, &stackSize);
// Glibc prior to 2.27 reports the stack size and base including the guard
// region, so we need to compensate for it to get accurate accounting.
// Also, this behavior difference isn't guarded by a versioned symbol, so we
// actually need to check the runtime glibc version, not the version we were
// compiled against.
static bool sAdjustForGuardSize = ({
#ifdef __GLIBC__
unsigned major, minor;
sscanf(gnu_get_libc_version(), "%u.%u", &major, &minor) < 2 ||
major < 2 || (major == 2 && minor < 27);
#else
false;
#endif
});
if (sAdjustForGuardSize) {
size_t guardSize;
pthread_attr_getguardsize(&attr, &guardSize);
// Note: This assumes that the stack grows down, as is the case on all of
// our tier 1 platforms. On platforms where the stack grows up, the
// mStackBase adjustment is unnecessary, but doesn't cause any harm other
// than under-counting stack memory usage by one page.
mStackBase = reinterpret_cast<char*>(mStackBase) + guardSize;
stackSize -= guardSize;
}
mStackSize = stackSize;
// This is a bit of a hack.
//
// We really do want the NOHUGEPAGE flag on our thread stacks, since we
// don't expect any of them to need anywhere near 2MB of space. But setting
// it here is too late to have an effect, since the first stack page has
// already been faulted in existence, and NSPR doesn't give us a way to set
// it beforehand.
//
// What this does get us, however, is a different set of VM flags on our
// thread stacks compared to normal heap memory. Which makes the Linux
// kernel report them as separate regions, even when they are adjacent to
// heap memory. This allows us to accurately track the actual memory
// consumption of our allocated stacks.
madvise(mStackBase, stackSize, MADV_NOHUGEPAGE);
pthread_attr_destroy(&attr);
#elif defined(XP_WIN)
static const DynamicallyLinkedFunctionPtr<GetCurrentThreadStackLimitsFn>
sGetStackLimits(L"kernel32.dll", "GetCurrentThreadStackLimits");
if (sGetStackLimits) {
ULONG_PTR stackBottom, stackTop;
sGetStackLimits(&stackBottom, &stackTop);
mStackBase = reinterpret_cast<void*>(stackBottom);
mStackSize = stackTop - stackBottom;
}
#endif
}
OffTheBooksMutexAutoLock mal(ThreadListMutex());
ThreadList().insertBack(this);
}
//-----------------------------------------------------------------------------
// Tell the crash reporter to save a memory report if our heuristics determine
@ -687,17 +670,7 @@ nsThread::~nsThread()
{
NS_ASSERTION(mRequestedShutdownContexts.IsEmpty(),
"shouldn't be waiting on other threads to shutdown");
// We shouldn't need to lock before checking isInList at this point. We're
// destroying the last reference to this object, so there's no way for anyone
// else to remove it in the middle of our check. And the not-in-list state is
// determined the element's next and previous members pointing to itself, so a
// non-atomic update to an adjacent member won't affect the outcome either.
if (isInList()) {
OffTheBooksMutexAutoLock mal(ThreadListMutex());
removeFrom(ThreadList());
}
MOZ_ASSERT(!isInList());
#ifdef DEBUG
// We deliberately leak these so they can be tracked by the leak checker.
// If you're having nsThreadShutdownContext leaks, you can set:
@ -731,6 +704,11 @@ nsThread::Init(const nsACString& aName)
return NS_ERROR_OUT_OF_MEMORY;
}
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
ThreadList().insertBack(this);
}
// ThreadFunc will wait for this event to be run before it tries to access
// mThread. By delaying insertion of this event into the queue, we ensure
// that mThread is set properly.
@ -750,7 +728,6 @@ nsThread::InitCurrentThread()
mThread = PR_GetCurrentThread();
mVirtualThread = GetCurrentVirtualThread();
SetupCurrentThreadForChaosMode();
InitCommon();
nsThreadManager::get().RegisterCurrentThread(*this);
return NS_OK;
@ -879,13 +856,6 @@ nsThread::ShutdownComplete(NotNull<nsThreadShutdownContext*> aContext)
MOZ_ASSERT(mThread);
MOZ_ASSERT(aContext->mTerminatingThread == this);
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
if (isInList()) {
removeFrom(ThreadList());
}
}
if (aContext->mAwaitingShutdownAck) {
// We're in a synchronous shutdown, so tell whatever is up the stack that
// we're done and unwind the stack so it can call us again.

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

@ -66,12 +66,6 @@ public:
// Initialize this as a wrapper for the current PRThread.
nsresult InitCurrentThread();
private:
// Initializes the mThreadId and stack base/size members, and adds the thread
// to the ThreadList().
void InitCommon();
public:
// The PRThread corresponding to this thread.
PRThread* GetPRThread()
{
@ -176,11 +170,8 @@ protected:
struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
friend class nsThreadManager;
static mozilla::OffTheBooksMutex& ThreadListMutex();
static mozilla::LinkedList<nsThread>& ThreadList();
static void ClearThreadList();
RefPtr<mozilla::SynchronizedEventQueue> mEvents;
RefPtr<mozilla::ThreadEventTarget> mEventTarget;
@ -214,8 +205,6 @@ protected:
// Set to true if this thread creates a JSRuntime.
bool mCanInvokeJS;
bool mHasTLSEntry = false;
// Used to track which event is being executed by ProcessNextEvent
nsCOMPtr<nsIRunnable> mCurrentEvent;

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

@ -94,27 +94,12 @@ AssertIsOnMainThread()
typedef nsTArray<NotNull<RefPtr<nsThread>>> nsThreadArray;
static bool sShutdownComplete;
//-----------------------------------------------------------------------------
/* static */ void
nsThreadManager::ReleaseThread(void* aData)
static void
ReleaseObject(void* aData)
{
if (sShutdownComplete) {
// We've already completed shutdown and released the references to all or
// our TLS wrappers. Don't try to release them again.
return;
}
auto* thread = static_cast<nsThread*>(aData);
get().UnregisterCurrentThread(*thread, true);
if (thread->mHasTLSEntry) {
thread->mHasTLSEntry = false;
thread->Release();
}
static_cast<nsISupports*>(aData)->Release();
}
// statically allocated instance
@ -251,7 +236,7 @@ nsThreadManager::Init()
Scheduler::EventLoopActivation::Init();
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseThread) == PR_FAILURE) {
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE) {
return NS_ERROR_FAILURE;
}
@ -319,34 +304,32 @@ nsThreadManager::Shutdown()
// Empty the main thread event queue before we begin shutting down threads.
NS_ProcessPendingEvents(mMainThread);
// We gather the threads from the hashtable into a list, so that we avoid
// holding the hashtable lock while calling nsIThread::Shutdown.
nsThreadArray threads;
{
// We gather the threads from the hashtable into a list, so that we avoid
// holding the hashtable lock while calling nsIThread::Shutdown.
nsThreadArray threads;
{
OffTheBooksMutexAutoLock lock(mLock);
for (auto iter = mThreadsByPRThread.Iter(); !iter.Done(); iter.Next()) {
RefPtr<nsThread>& thread = iter.Data();
threads.AppendElement(WrapNotNull(thread));
iter.Remove();
}
OffTheBooksMutexAutoLock lock(mLock);
for (auto iter = mThreadsByPRThread.Iter(); !iter.Done(); iter.Next()) {
RefPtr<nsThread>& thread = iter.Data();
threads.AppendElement(WrapNotNull(thread));
iter.Remove();
}
}
// It's tempting to walk the list of threads here and tell them each to stop
// accepting new events, but that could lead to badness if one of those
// threads is stuck waiting for a response from another thread. To do it
// right, we'd need some way to interrupt the threads.
//
// Instead, we process events on the current thread while waiting for threads
// to shutdown. This means that we have to preserve a mostly functioning
// world until such time as the threads exit.
// It's tempting to walk the list of threads here and tell them each to stop
// accepting new events, but that could lead to badness if one of those
// threads is stuck waiting for a response from another thread. To do it
// right, we'd need some way to interrupt the threads.
//
// Instead, we process events on the current thread while waiting for threads
// to shutdown. This means that we have to preserve a mostly functioning
// world until such time as the threads exit.
// Shutdown all threads that require it (join with threads that we created).
for (uint32_t i = 0; i < threads.Length(); ++i) {
NotNull<nsThread*> thread = threads[i];
if (thread->ShutdownRequired()) {
thread->Shutdown();
}
// Shutdown all threads that require it (join with threads that we created).
for (uint32_t i = 0; i < threads.Length(); ++i) {
NotNull<nsThread*> thread = threads[i];
if (thread->ShutdownRequired()) {
thread->Shutdown();
}
}
@ -377,24 +360,6 @@ nsThreadManager::Shutdown()
// Remove the TLS entry for the main thread.
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
{
// Cleanup the last references to any threads which haven't shut down yet.
nsTArray<RefPtr<nsThread>> threads;
for (auto* thread : nsThread::Enumerate()) {
if (thread->mHasTLSEntry) {
threads.AppendElement(dont_AddRef(thread));
thread->mHasTLSEntry = false;
}
}
}
// xpcshell tests sometimes leak the main thread. They don't enable leak
// checking, so that doesn't cause the test to fail, but leaving the entry in
// the thread list triggers an assertion, which does.
nsThread::ClearThreadList();
sShutdownComplete = true;
}
void
@ -412,28 +377,21 @@ nsThreadManager::RegisterCurrentThread(nsThread& aThread)
mThreadsByPRThread.Put(aThread.GetPRThread(), &aThread); // XXX check OOM?
aThread.AddRef(); // for TLS entry
aThread.mHasTLSEntry = true;
PR_SetThreadPrivate(mCurThreadIndex, &aThread);
}
void
nsThreadManager::UnregisterCurrentThread(nsThread& aThread, bool aIfExists)
nsThreadManager::UnregisterCurrentThread(nsThread& aThread)
{
MOZ_ASSERT(aThread.GetPRThread() == PR_GetCurrentThread(), "bad aThread");
{
OffTheBooksMutexAutoLock lock(mLock);
OffTheBooksMutexAutoLock lock(mLock);
if (aIfExists && !mThreadsByPRThread.GetWeak(aThread.GetPRThread())) {
return;
}
--mCurrentNumberOfThreads;
mThreadsByPRThread.Remove(aThread.GetPRThread());
}
--mCurrentNumberOfThreads;
mThreadsByPRThread.Remove(aThread.GetPRThread());
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
// Ref-count balanced via ReleaseThread
// Ref-count balanced via ReleaseObject
}
nsThread*
@ -483,13 +441,7 @@ nsThreadManager::GetCurrentThread()
bool
nsThreadManager::IsNSThread() const
{
if (!mInitialized) {
return false;
}
if (auto* thread = (nsThread*)PR_GetThreadPrivate(mCurThreadIndex)) {
return thread->mShutdownRequired;
}
return false;
return mInitialized && !!PR_GetThreadPrivate(mCurThreadIndex);
}
NS_IMETHODIMP

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

@ -36,7 +36,7 @@ public:
// Called by nsThread to inform the ThreadManager it is going away. This
// method must be called when the given thread is the current thread.
void UnregisterCurrentThread(nsThread& aThread, bool aIfExists = false);
void UnregisterCurrentThread(nsThread& aThread);
// Returns the current thread. Returns null if OOM or if ThreadManager isn't
// initialized. Creates the nsThread if one does not exist yet.
@ -85,8 +85,6 @@ private:
SpinEventLoopUntilInternal(nsINestedEventLoopCondition* aCondition,
bool aCheckingShutdown);
static void ReleaseThread(void* aData);
nsRefPtrHashtable<nsPtrHashKey<PRThread>, nsThread> mThreadsByPRThread;
unsigned mCurThreadIndex; // thread-local-storage index
RefPtr<nsThread> mMainThread;