mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge mozilla-central and b2g-inbound
This commit is contained in:
commit
ae834488ea
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "e3564b8656fcd189d4a83379e94bef1ab7d657b5",
|
||||
"revision": "d9d422e52a7a45dfb075fd2bf4fd48c956276baa",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -1578,27 +1578,31 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetDefaultAdapterPath(BluetoothValue& aValue, nsString& aError)
|
||||
static void
|
||||
OnDefaultAdapterReply(DBusMessage* aReply, void* aData)
|
||||
{
|
||||
// This could block. It should never be run on the main thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
|
||||
|
||||
if (!aReply || dbus_message_is_error(aReply, DBUS_ERROR_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
|
||||
DBusMessage* msg;
|
||||
bool success = gThreadConnection->SendWithError(&msg, &err, 1000, "/",
|
||||
DBUS_MANAGER_IFACE,
|
||||
"DefaultAdapter",
|
||||
DBUS_TYPE_INVALID);
|
||||
NS_ENSURE_TRUE(success, false);
|
||||
BluetoothValue v;
|
||||
nsAutoString errorString;
|
||||
|
||||
UnpackObjectPathMessage(msg, &err, aValue, aError);
|
||||
UnpackObjectPathMessage(aReply, &err, v, errorString);
|
||||
|
||||
dbus_message_unref(msg);
|
||||
if (!errorString.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return aError.IsEmpty();
|
||||
nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
|
||||
if (NS_FAILED(NS_DispatchToMainThread(b))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1669,17 +1673,17 @@ BluetoothDBusService::StartInternal()
|
||||
sPairingReqTable = new nsDataHashtable<nsStringHashKey, DBusMessage* >;
|
||||
}
|
||||
|
||||
BluetoothValue v;
|
||||
nsAutoString replyError;
|
||||
if (!GetDefaultAdapterPath(v, replyError)) {
|
||||
// Adapter path is not ready yet
|
||||
// Let's do PrepareAdapterRunnable when we receive signal 'AdapterAdded'
|
||||
} else {
|
||||
// Adapter path has been ready. let's do PrepareAdapterRunnable now
|
||||
nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
|
||||
if (NS_FAILED(NS_DispatchToMainThread(b))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
// Normally we'll receive the signal 'AdapterAdded' for the default
|
||||
// adapter from the DBus daemon during start up. If we restart after
|
||||
// a crash, the default adapter might already be available, so we ask
|
||||
// the daemon explicitly here.
|
||||
bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
|
||||
1000, "/",
|
||||
DBUS_ADAPTER_IFACE,
|
||||
"DefaultAdapter",
|
||||
DBUS_TYPE_INVALID);
|
||||
if (!success) {
|
||||
BT_WARNING("Failed to query default adapter!");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -18,7 +18,6 @@
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
@ -1768,8 +1767,7 @@ RILContentHelper.prototype = {
|
||||
return contact;
|
||||
});
|
||||
|
||||
this.fireRequestSuccess(message.requestId,
|
||||
ObjectWrapper.wrap(result, window));
|
||||
this.fireRequestSuccess(message.requestId, result);
|
||||
},
|
||||
|
||||
handleVoicemailNotification: function handleVoicemailNotification(message) {
|
||||
|
@ -3237,8 +3237,10 @@ RILNetworkInterface.prototype = {
|
||||
classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
|
||||
classDescription: "RILNetworkInterface",
|
||||
interfaces: [Ci.nsINetworkInterface,
|
||||
Ci.nsIRilNetworkInterface,
|
||||
Ci.nsIRILDataCallback]}),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
|
||||
Ci.nsIRilNetworkInterface,
|
||||
Ci.nsIRILDataCallback]),
|
||||
|
||||
// nsINetworkInterface
|
||||
@ -3304,6 +3306,15 @@ RILNetworkInterface.prototype = {
|
||||
return this.apnSetting.port || '';
|
||||
},
|
||||
|
||||
get serviceId() {
|
||||
return this.radioInterface.clientId;
|
||||
},
|
||||
|
||||
get iccId() {
|
||||
let iccInfo = this.radioInterface.rilContext.iccInfo;
|
||||
return iccInfo && iccInfo.iccid;
|
||||
},
|
||||
|
||||
debug: function debug(s) {
|
||||
dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" +
|
||||
this.type + "]: " + s + "\n");
|
||||
|
@ -3,11 +3,19 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsINetworkManager.idl"
|
||||
|
||||
interface nsIDOMMozIccInfo;
|
||||
interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIMobileMessageCallback;
|
||||
|
||||
[scriptable, uuid(a15769f1-538e-4b4b-81da-c52866d38f88)]
|
||||
interface nsIRilNetworkInterface : nsINetworkInterface
|
||||
{
|
||||
readonly attribute unsigned long serviceId;
|
||||
readonly attribute DOMString iccId;
|
||||
};
|
||||
|
||||
[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
|
||||
interface nsIRILDataCallInfo : nsISupports
|
||||
{
|
||||
|
@ -86,6 +86,9 @@ let RILQUIRKS_EXTRA_UINT32_2ND_CALL = libcutils.property_get("ro.moz.ril.extra_i
|
||||
// On the emulator we support querying the number of lock retries
|
||||
let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true";
|
||||
|
||||
// Ril quirk to Send STK Profile Download
|
||||
let RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true";
|
||||
|
||||
// Marker object.
|
||||
let PENDING_NETWORK_TYPE = {};
|
||||
|
||||
@ -3014,10 +3017,14 @@ let RIL = {
|
||||
ICCRecordHelper.readICCPhase();
|
||||
ICCRecordHelper.fetchICCRecords();
|
||||
} else if (this.appType == CARD_APPTYPE_USIM) {
|
||||
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
|
||||
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
|
||||
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
|
||||
}
|
||||
ICCRecordHelper.fetchICCRecords();
|
||||
} else if (this.appType == CARD_APPTYPE_RUIM) {
|
||||
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
|
||||
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
|
||||
this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
|
||||
}
|
||||
RuimRecordHelper.fetchRuimRecords();
|
||||
}
|
||||
this.reportStkServiceIsRunning();
|
||||
@ -10382,7 +10389,7 @@ let ComprehensionTlvHelper = {
|
||||
} else {
|
||||
RIL.sendStkTerminalResponse({
|
||||
resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD});
|
||||
throw new Error("Invalid octet in Comprehension TLV :" + length);
|
||||
throw new Error("Invalid octet in Comprehension TLV :" + temp);
|
||||
}
|
||||
|
||||
let ctlv = {
|
||||
@ -11026,7 +11033,8 @@ let ICCRecordHelper = {
|
||||
let phase = GsmPDUHelper.readHexOctet();
|
||||
// If EF_phase is coded '03' or greater, an ME supporting STK shall
|
||||
// perform the PROFILE DOWNLOAD procedure.
|
||||
if (phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
|
||||
if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD &&
|
||||
phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
|
||||
RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,31 @@ function newUint8SupportOutgoingIndexWorker() {
|
||||
}
|
||||
|
||||
// Test RIL requests related to STK.
|
||||
/**
|
||||
* Verify if RIL.sendStkTerminalProfile be called.
|
||||
*/
|
||||
add_test(function test_if_send_stk_terminal_profile() {
|
||||
let worker = newUint8Worker();
|
||||
let profileSend = false;
|
||||
worker.RIL.sendStkTerminalProfile = function (data) {
|
||||
profileSend = true;
|
||||
};
|
||||
|
||||
let iccStatus = {
|
||||
gsmUmtsSubscriptionAppIndex: 0,
|
||||
apps: [{
|
||||
app_state: CARD_APPSTATE_READY,
|
||||
app_type: CARD_APPTYPE_USIM
|
||||
}],
|
||||
};
|
||||
worker.RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = false;
|
||||
|
||||
worker.RIL._processICCStatus(iccStatus);
|
||||
|
||||
do_check_eq(profileSend, false);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify RIL.sendStkTerminalProfile
|
||||
|
@ -117,7 +117,11 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
|
||||
apzc = container->GetAsyncPanZoomController();
|
||||
|
||||
bool newApzc = (apzc == nullptr);
|
||||
// The APZC we get off the layer may have been destroyed previously if the layer was inactive
|
||||
// or omitted from the layer tree for whatever reason from a layers update. If it later comes
|
||||
// back it will have a reference to a destroyed APZC and so we need to throw that out and make
|
||||
// a new one.
|
||||
bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
|
||||
if (newApzc) {
|
||||
apzc = new AsyncPanZoomController(aLayersId, this, state->mController,
|
||||
AsyncPanZoomController::USE_GESTURE_DETECTOR);
|
||||
|
@ -326,6 +326,12 @@ AsyncPanZoomController::Destroy()
|
||||
mTreeManager = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::IsDestroyed()
|
||||
{
|
||||
return mTreeManager == nullptr;
|
||||
}
|
||||
|
||||
/* static */float
|
||||
AsyncPanZoomController::GetTouchStartTolerance()
|
||||
{
|
||||
|
@ -203,6 +203,11 @@ public:
|
||||
*/
|
||||
void Destroy();
|
||||
|
||||
/**
|
||||
* Returns true if Destroy() has already been called on this APZC instance.
|
||||
*/
|
||||
bool IsDestroyed();
|
||||
|
||||
/**
|
||||
* Returns the incremental transformation corresponding to the async pan/zoom
|
||||
* in progress. That is, when this transform is multiplied with the layer's
|
||||
|
@ -69,56 +69,31 @@
|
||||
|
||||
#define DEFAULT_INITIAL_POLLFD_COUNT 8
|
||||
|
||||
// Functions for converting between unix events in the poll struct,
|
||||
// and their dbus definitions
|
||||
|
||||
enum DBusEventTypes {
|
||||
DBUS_EVENT_LOOP_EXIT = 1,
|
||||
DBUS_EVENT_LOOP_ADD = 2,
|
||||
DBUS_EVENT_LOOP_REMOVE = 3,
|
||||
DBUS_EVENT_LOOP_WAKEUP = 4
|
||||
};
|
||||
|
||||
static unsigned int UnixEventsToDBusFlags(short events)
|
||||
{
|
||||
return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
|
||||
(events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
|
||||
(events & DBUS_WATCH_ERROR ? POLLERR : 0) |
|
||||
(events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
|
||||
}
|
||||
|
||||
static short DBusFlagsToUnixEvents(unsigned int flags)
|
||||
{
|
||||
return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
|
||||
(flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
|
||||
(flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
|
||||
(flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
struct PollFdComparator {
|
||||
bool Equals(const pollfd& a, const pollfd& b) const {
|
||||
return ((a.fd == b.fd) &&
|
||||
(a.events == b.events));
|
||||
}
|
||||
bool LessThan(const pollfd& a, const pollfd&b) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// DBus Thread Class prototype
|
||||
|
||||
struct DBusThread : public RawDBusConnection
|
||||
class DBusWatcher : public RawDBusConnection
|
||||
{
|
||||
DBusThread();
|
||||
~DBusThread();
|
||||
public:
|
||||
DBusWatcher()
|
||||
{ }
|
||||
|
||||
~DBusWatcher()
|
||||
{ }
|
||||
|
||||
bool Initialize();
|
||||
void CleanUp();
|
||||
|
||||
void WakeUp();
|
||||
bool Stop();
|
||||
|
||||
bool Poll();
|
||||
|
||||
bool AddWatch(DBusWatch* aWatch);
|
||||
void RemoveWatch(DBusWatch* aWatch);
|
||||
|
||||
void HandleWatchAdd();
|
||||
void HandleWatchRemove();
|
||||
|
||||
// Information about the sockets we're polling. Socket counts
|
||||
// increase/decrease depending on how many add/remove watch signals
|
||||
@ -131,131 +106,302 @@ struct DBusThread : public RawDBusConnection
|
||||
ScopedClose mControlFdR;
|
||||
ScopedClose mControlFdW;
|
||||
|
||||
protected:
|
||||
private:
|
||||
struct PollFdComparator {
|
||||
bool Equals(const pollfd& a, const pollfd& b) const {
|
||||
return ((a.fd == b.fd) && (a.events == b.events));
|
||||
}
|
||||
bool LessThan(const pollfd& a, const pollfd&b) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
enum DBusEventTypes {
|
||||
DBUS_EVENT_LOOP_EXIT = 1,
|
||||
DBUS_EVENT_LOOP_ADD = 2,
|
||||
DBUS_EVENT_LOOP_REMOVE = 3,
|
||||
DBUS_EVENT_LOOP_WAKEUP = 4
|
||||
};
|
||||
|
||||
static unsigned int UnixEventsToDBusFlags(short events);
|
||||
static short DBusFlagsToUnixEvents(unsigned int flags);
|
||||
|
||||
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void DBusWakeupFunction(void* aData);
|
||||
|
||||
bool SetUp();
|
||||
};
|
||||
|
||||
// DBus utility functions
|
||||
// Free statics, as they're used as function pointers in dbus setup
|
||||
|
||||
static dbus_bool_t
|
||||
AddWatch(DBusWatch *aWatch, void *aData)
|
||||
bool
|
||||
DBusWatcher::Initialize()
|
||||
{
|
||||
DBusThread *dbt = (DBusThread *)aData;
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
// note that we can't just send the watch and inspect it later
|
||||
// because we may get a removeWatch call before this data is reacted
|
||||
// to by our eventloop and remove this watch.. reading the add first
|
||||
// and then inspecting the recently deceased watch would be bad.
|
||||
char control = DBUS_EVENT_LOOP_ADD;
|
||||
if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
|
||||
LOG("Cannot write DBus add watch control data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(aWatch);
|
||||
if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
|
||||
LOG("Cannot write DBus add watch descriptor data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(aWatch);
|
||||
if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
|
||||
LOG("Cannot write DBus add watch flag data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
|
||||
LOG("Cannot write DBus add watch struct data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
if (!SetUp()) {
|
||||
CleanUp();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveWatch(DBusWatch *aWatch, void *aData)
|
||||
void
|
||||
DBusWatcher::CleanUp()
|
||||
{
|
||||
DBusThread *dbt = (DBusThread *)aData;
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
char control = DBUS_EVENT_LOOP_REMOVE;
|
||||
if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
|
||||
dbus_connection_set_wakeup_main_function(mConnection, nullptr,
|
||||
nullptr, nullptr);
|
||||
dbus_bool_t success = dbus_connection_set_watch_functions(mConnection,
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr,
|
||||
nullptr);
|
||||
if (success != TRUE) {
|
||||
NS_WARNING("dbus_connection_set_watch_functions failed");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
LOG("Removing DBus Sockets\n");
|
||||
#endif
|
||||
if (mControlFdW.get()) {
|
||||
mControlFdW.dispose();
|
||||
}
|
||||
if (mControlFdR.get()) {
|
||||
mControlFdR.dispose();
|
||||
}
|
||||
mPollData.Clear();
|
||||
|
||||
// DBusWatch pointers are maintained by DBus, so we won't leak by
|
||||
// clearing.
|
||||
mWatchData.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::WakeUp()
|
||||
{
|
||||
static const char control = DBUS_EVENT_LOOP_WAKEUP;
|
||||
|
||||
struct pollfd fds = {
|
||||
mControlFdW.get(),
|
||||
POLLOUT,
|
||||
0
|
||||
};
|
||||
|
||||
int nfds = TEMP_FAILURE_RETRY(poll(&fds, 1, 0));
|
||||
NS_ENSURE_TRUE_VOID(nfds == 1);
|
||||
NS_ENSURE_TRUE_VOID(fds.revents == POLLOUT);
|
||||
|
||||
ssize_t res = TEMP_FAILURE_RETRY(
|
||||
write(mControlFdW.get(), &control, sizeof(control)));
|
||||
if (res < 0) {
|
||||
NS_WARNING("Cannot write wakeup bit to DBus controller!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DBusWatcher::Stop()
|
||||
{
|
||||
static const char data = DBUS_EVENT_LOOP_EXIT;
|
||||
|
||||
ssize_t res =
|
||||
TEMP_FAILURE_RETRY(write(mControlFdW.get(), &data, sizeof(data)));
|
||||
NS_ENSURE_TRUE(res == 1, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DBusWatcher::Poll()
|
||||
{
|
||||
int res = TEMP_FAILURE_RETRY(poll(mPollData.Elements(),
|
||||
mPollData.Length(), -1));
|
||||
NS_ENSURE_TRUE(res > 0, false);
|
||||
|
||||
bool continueThread = true;
|
||||
|
||||
nsTArray<pollfd>::size_type i = 0;
|
||||
|
||||
while (i < mPollData.Length()) {
|
||||
if (mPollData[i].revents == POLLIN) {
|
||||
if (mPollData[i].fd == mControlFdR.get()) {
|
||||
char data;
|
||||
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &data, sizeof(data)));
|
||||
NS_ENSURE_TRUE(res > 0, NS_OK);
|
||||
|
||||
switch (data) {
|
||||
case DBUS_EVENT_LOOP_EXIT:
|
||||
continueThread = false;
|
||||
break;
|
||||
case DBUS_EVENT_LOOP_ADD:
|
||||
HandleWatchAdd();
|
||||
break;
|
||||
case DBUS_EVENT_LOOP_REMOVE:
|
||||
HandleWatchRemove();
|
||||
// don't increment i, or we'll skip one element
|
||||
continue;
|
||||
case DBUS_EVENT_LOOP_WAKEUP:
|
||||
NS_ProcessPendingEvents(NS_GetCurrentThread(),
|
||||
PR_INTERVAL_NO_TIMEOUT);
|
||||
break;
|
||||
default:
|
||||
#if DEBUG
|
||||
nsCString warning("unknown command ");
|
||||
warning.AppendInt(data);
|
||||
NS_WARNING(warning.get());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
short events = mPollData[i].revents;
|
||||
unsigned int flags = UnixEventsToDBusFlags(events);
|
||||
dbus_watch_handle(mWatchData[i], flags);
|
||||
mPollData[i].revents = 0;
|
||||
// Break at this point since we don't know if the operation
|
||||
// was destructive
|
||||
break;
|
||||
}
|
||||
|
||||
DBusDispatchStatus dbusDispatchStatus;
|
||||
do {
|
||||
dbusDispatchStatus = dbus_connection_dispatch(GetConnection());
|
||||
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return continueThread;
|
||||
}
|
||||
|
||||
bool
|
||||
DBusWatcher::AddWatch(DBusWatch* aWatch)
|
||||
{
|
||||
static const char control = DBUS_EVENT_LOOP_ADD;
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch) == FALSE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// note that we can't just send the watch and inspect it later
|
||||
// because we may get a removeWatch call before this data is reacted
|
||||
// to by our eventloop and remove this watch.. reading the add first
|
||||
// and then inspecting the recently deceased watch would be bad.
|
||||
ssize_t res =
|
||||
TEMP_FAILURE_RETRY(write(mControlFdW.get(),&control, sizeof(control)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus add watch control data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(aWatch);
|
||||
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus add watch descriptor data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(aWatch);
|
||||
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus add watch flag data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &aWatch, sizeof(aWatch)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus add watch struct data to socket!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::RemoveWatch(DBusWatch* aWatch)
|
||||
{
|
||||
static const char control = DBUS_EVENT_LOOP_REMOVE;
|
||||
|
||||
ssize_t res =
|
||||
TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus remove watch control data to socket!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(aWatch);
|
||||
if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
|
||||
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &fd, sizeof(fd)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus remove watch descriptor data to socket!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(aWatch);
|
||||
if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
|
||||
res = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &flags, sizeof(flags)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot write DBus remove watch flag data to socket!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ToggleWatch(DBusWatch *aWatch, void *aData)
|
||||
void
|
||||
DBusWatcher::HandleWatchAdd()
|
||||
{
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
AddWatch(aWatch, aData);
|
||||
} else {
|
||||
RemoveWatch(aWatch, aData);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HandleWatchAdd(DBusThread* aDbt)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
int newFD;
|
||||
unsigned int flags;
|
||||
if (read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
|
||||
int fd;
|
||||
ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot read DBus watch add descriptor data from socket!\n");
|
||||
return;
|
||||
}
|
||||
if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
|
||||
|
||||
unsigned int flags;
|
||||
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot read DBus watch add flag data from socket!\n");
|
||||
return;
|
||||
}
|
||||
if (read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
|
||||
|
||||
DBusWatch* watch;
|
||||
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &watch, sizeof(watch)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot read DBus watch add watch data from socket!\n");
|
||||
return;
|
||||
}
|
||||
short events = DBusFlagsToUnixEvents(flags);
|
||||
|
||||
pollfd p;
|
||||
p.fd = newFD;
|
||||
p.revents = 0;
|
||||
p.events = events;
|
||||
if (aDbt->mPollData.Contains(p, PollFdComparator())) return;
|
||||
aDbt->mPollData.AppendElement(p);
|
||||
aDbt->mWatchData.AppendElement(watch);
|
||||
struct pollfd p = {
|
||||
fd, // .fd
|
||||
DBusFlagsToUnixEvents(flags), // .events
|
||||
0 // .revents
|
||||
};
|
||||
if (mPollData.Contains(p, PollFdComparator())) {
|
||||
return;
|
||||
}
|
||||
mPollData.AppendElement(p);
|
||||
mWatchData.AppendElement(watch);
|
||||
}
|
||||
|
||||
static void
|
||||
HandleWatchRemove(DBusThread* aDbt)
|
||||
void
|
||||
DBusWatcher::HandleWatchRemove()
|
||||
{
|
||||
int removeFD;
|
||||
unsigned int flags;
|
||||
|
||||
if (read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
|
||||
int fd;
|
||||
ssize_t res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &fd, sizeof(fd)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot read DBus watch remove descriptor data from socket!\n");
|
||||
return;
|
||||
}
|
||||
if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
|
||||
|
||||
unsigned int flags;
|
||||
res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &flags, sizeof(flags)));
|
||||
if (res < 0) {
|
||||
LOG("Cannot read DBus watch remove flag data from socket!\n");
|
||||
return;
|
||||
}
|
||||
short events = DBusFlagsToUnixEvents(flags);
|
||||
pollfd p;
|
||||
p.fd = removeFD;
|
||||
p.events = events;
|
||||
int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
|
||||
|
||||
struct pollfd p = {
|
||||
fd, // .fd
|
||||
DBusFlagsToUnixEvents(flags), // .events
|
||||
0 // .revents
|
||||
};
|
||||
int index = mPollData.IndexOf(p, 0, PollFdComparator());
|
||||
// There are times where removes can be requested for watches that
|
||||
// haven't been added (for example, whenever gecko comes up after
|
||||
// adapters have already been enabled), so check to make sure we're
|
||||
@ -264,34 +410,74 @@ HandleWatchRemove(DBusThread* aDbt)
|
||||
LOG("DBus requested watch removal of non-existant socket, ignoring...");
|
||||
return;
|
||||
}
|
||||
aDbt->mPollData.RemoveElementAt(index);
|
||||
mPollData.RemoveElementAt(index);
|
||||
|
||||
// DBusWatch pointers are maintained by DBus, so we won't leak by
|
||||
// removing.
|
||||
aDbt->mWatchData.RemoveElementAt(index);
|
||||
mWatchData.RemoveElementAt(index);
|
||||
}
|
||||
|
||||
static
|
||||
void DBusWakeup(void* aData)
|
||||
// Flag conversion
|
||||
|
||||
unsigned int
|
||||
DBusWatcher::UnixEventsToDBusFlags(short events)
|
||||
{
|
||||
return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
|
||||
(events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
|
||||
(events & DBUS_WATCH_ERROR ? POLLERR : 0) |
|
||||
(events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
|
||||
}
|
||||
|
||||
short
|
||||
DBusWatcher::DBusFlagsToUnixEvents(unsigned int flags)
|
||||
{
|
||||
return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
|
||||
(flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
|
||||
(flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
|
||||
(flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
|
||||
}
|
||||
|
||||
// DBus utility functions, used as function pointers in DBus setup
|
||||
|
||||
dbus_bool_t
|
||||
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
DBusThread* dbusThread = static_cast<DBusThread*>(aData);
|
||||
dbusThread->WakeUp();
|
||||
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
|
||||
return dbusWatcher->AddWatch(aWatch);
|
||||
}
|
||||
|
||||
// DBus Thread Implementation
|
||||
|
||||
DBusThread::DBusThread()
|
||||
void
|
||||
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
|
||||
dbusWatcher->RemoveWatch(aWatch);
|
||||
}
|
||||
|
||||
DBusThread::~DBusThread()
|
||||
void
|
||||
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->AddWatch(aWatch);
|
||||
} else {
|
||||
dbusWatcher->RemoveWatch(aWatch);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::DBusWakeupFunction(void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
DBusWatcher* dbusWatcher = static_cast<DBusWatcher*>(aData);
|
||||
dbusWatcher->WakeUp();
|
||||
}
|
||||
|
||||
bool
|
||||
DBusThread::SetUp()
|
||||
DBusWatcher::SetUp()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
@ -315,7 +501,7 @@ DBusThread::SetUp()
|
||||
mControlFdR.rwget() = sockets[0];
|
||||
mControlFdW.rwget() = sockets[1];
|
||||
|
||||
pollfd *p = mPollData.AppendElement();
|
||||
pollfd* p = mPollData.AppendElement();
|
||||
|
||||
p->fd = mControlFdR.get();
|
||||
p->events = POLLIN;
|
||||
@ -335,161 +521,55 @@ DBusThread::SetUp()
|
||||
}
|
||||
|
||||
dbus_bool_t success =
|
||||
dbus_connection_set_watch_functions(mConnection, AddWatch, RemoveWatch,
|
||||
ToggleWatch, this, nullptr);
|
||||
dbus_connection_set_watch_functions(mConnection, AddWatchFunction,
|
||||
RemoveWatchFunction,
|
||||
ToggleWatchFunction, this, nullptr);
|
||||
NS_ENSURE_TRUE(success == TRUE, false);
|
||||
|
||||
dbus_connection_set_wakeup_main_function(mConnection, DBusWakeup, this, nullptr);
|
||||
|
||||
dbus_connection_set_wakeup_main_function(mConnection, DBusWakeupFunction,
|
||||
this, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DBusThread::Initialize()
|
||||
{
|
||||
if (!SetUp()) {
|
||||
CleanUp();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DBusThread::CleanUp()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_connection_set_wakeup_main_function(mConnection, nullptr, nullptr, nullptr);
|
||||
|
||||
dbus_bool_t success = dbus_connection_set_watch_functions(mConnection, nullptr,
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (success != TRUE) {
|
||||
NS_WARNING("dbus_connection_set_watch_functions failed");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
LOG("Removing DBus Sockets\n");
|
||||
#endif
|
||||
if (mControlFdW.get()) {
|
||||
mControlFdW.dispose();
|
||||
}
|
||||
if (mControlFdR.get()) {
|
||||
mControlFdR.dispose();
|
||||
}
|
||||
mPollData.Clear();
|
||||
|
||||
// DBusWatch pointers are maintained by DBus, so we won't leak by
|
||||
// clearing.
|
||||
mWatchData.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
DBusThread::WakeUp()
|
||||
{
|
||||
static const char control = DBUS_EVENT_LOOP_WAKEUP;
|
||||
|
||||
struct pollfd fds = {
|
||||
mControlFdW.get(),
|
||||
POLLOUT,
|
||||
0
|
||||
};
|
||||
|
||||
int nfds = TEMP_FAILURE_RETRY(poll(&fds, 1, 0));
|
||||
NS_ENSURE_TRUE_VOID(nfds == 1);
|
||||
NS_ENSURE_TRUE_VOID(fds.revents == POLLOUT);
|
||||
|
||||
ssize_t rv = TEMP_FAILURE_RETRY(write(mControlFdW.get(), &control, sizeof(control)));
|
||||
|
||||
if (rv < 0) {
|
||||
NS_WARNING("Cannot write wakeup bit to DBus controller!");
|
||||
}
|
||||
}
|
||||
|
||||
// Main task for polling the DBus system
|
||||
|
||||
class DBusPollTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DBusPollTask(DBusThread* aConnection)
|
||||
: mConnection(aConnection)
|
||||
DBusPollTask(DBusWatcher* aDBusWatcher)
|
||||
: mDBusWatcher(aDBusWatcher)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
bool exitThread = false;
|
||||
bool continueThread;
|
||||
|
||||
while (!exitThread) {
|
||||
do {
|
||||
continueThread = mDBusWatcher->Poll();
|
||||
} while (continueThread);
|
||||
|
||||
int res = TEMP_FAILURE_RETRY(poll(mConnection->mPollData.Elements(),
|
||||
mConnection->mPollData.Length(),
|
||||
-1));
|
||||
NS_ENSURE_TRUE(res > 0, NS_OK);
|
||||
mDBusWatcher->CleanUp();
|
||||
|
||||
nsTArray<pollfd>::size_type i = 0;
|
||||
nsIThread* thread;
|
||||
nsresult rv = NS_GetCurrentThread(&thread);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
while (i < mConnection->mPollData.Length()) {
|
||||
if (mConnection->mPollData[i].revents == POLLIN) {
|
||||
|
||||
if (mConnection->mPollData[i].fd == mConnection->mControlFdR.get()) {
|
||||
char data;
|
||||
res = TEMP_FAILURE_RETRY(read(mConnection->mControlFdR.get(), &data, sizeof(data)));
|
||||
NS_ENSURE_TRUE(res > 0, NS_OK);
|
||||
|
||||
switch (data) {
|
||||
case DBUS_EVENT_LOOP_EXIT:
|
||||
exitThread = true;
|
||||
break;
|
||||
case DBUS_EVENT_LOOP_ADD:
|
||||
HandleWatchAdd(mConnection);
|
||||
break;
|
||||
case DBUS_EVENT_LOOP_REMOVE:
|
||||
HandleWatchRemove(mConnection);
|
||||
// don't increment i, or we'll skip one element
|
||||
continue;
|
||||
case DBUS_EVENT_LOOP_WAKEUP:
|
||||
NS_ProcessPendingEvents(NS_GetCurrentThread(),
|
||||
PR_INTERVAL_NO_TIMEOUT);
|
||||
break;
|
||||
default:
|
||||
#if DEBUG
|
||||
nsCString warning("unknown command ");
|
||||
warning.AppendInt(data);
|
||||
NS_WARNING(warning.get());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
short events = mConnection->mPollData[i].revents;
|
||||
unsigned int flags = UnixEventsToDBusFlags(events);
|
||||
dbus_watch_handle(mConnection->mWatchData[i], flags);
|
||||
mConnection->mPollData[i].revents = 0;
|
||||
// Break at this point since we don't know if the operation
|
||||
// was destructive
|
||||
break;
|
||||
}
|
||||
while (dbus_connection_dispatch(mConnection->GetConnection()) ==
|
||||
DBUS_DISPATCH_DATA_REMAINS)
|
||||
{}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
mConnection->CleanUp();
|
||||
nsRefPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
|
||||
rv = NS_DispatchToMainThread(runnable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<DBusThread> mConnection;
|
||||
nsRefPtr<DBusWatcher> mDBusWatcher;
|
||||
};
|
||||
|
||||
static StaticRefPtr<DBusThread> gDBusThread;
|
||||
static StaticRefPtr<nsIThread> gDBusServiceThread;
|
||||
static StaticRefPtr<DBusWatcher> gDBusWatcher;
|
||||
static StaticRefPtr<nsIThread> gDBusServiceThread;
|
||||
|
||||
// Startup/Shutdown utility functions
|
||||
|
||||
@ -497,11 +577,11 @@ bool
|
||||
StartDBus()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(!gDBusThread, true);
|
||||
NS_ENSURE_TRUE(!gDBusWatcher, true);
|
||||
|
||||
nsRefPtr<DBusThread> dbusThread(new DBusThread());
|
||||
nsRefPtr<DBusWatcher> dbusWatcher(new DBusWatcher());
|
||||
|
||||
bool eventLoopStarted = dbusThread->Initialize();
|
||||
bool eventLoopStarted = dbusWatcher->Initialize();
|
||||
NS_ENSURE_TRUE(eventLoopStarted, false);
|
||||
|
||||
nsresult rv;
|
||||
@ -517,13 +597,13 @@ StartDBus()
|
||||
LOG("DBus Thread Starting\n");
|
||||
#endif
|
||||
|
||||
nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusThread));
|
||||
nsRefPtr<nsIRunnable> pollTask(new DBusPollTask(dbusWatcher));
|
||||
NS_ENSURE_TRUE(pollTask, false);
|
||||
|
||||
rv = gDBusServiceThread->Dispatch(pollTask, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
gDBusThread = dbusThread;
|
||||
gDBusWatcher = dbusWatcher;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -534,24 +614,15 @@ StopDBus()
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(gDBusServiceThread, true);
|
||||
|
||||
nsRefPtr<DBusThread> dbusThread(gDBusThread);
|
||||
gDBusThread = nullptr;
|
||||
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
|
||||
gDBusWatcher = nullptr;
|
||||
|
||||
if (dbusThread) {
|
||||
static const char data = DBUS_EVENT_LOOP_EXIT;
|
||||
ssize_t wret = TEMP_FAILURE_RETRY(write(dbusThread->mControlFdW.get(),
|
||||
&data, sizeof(data)));
|
||||
NS_ENSURE_TRUE(wret == 1, false);
|
||||
if (dbusWatcher && !dbusWatcher->Stop()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
|
||||
gDBusServiceThread = nullptr;
|
||||
|
||||
nsRefPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(dbusServiceThread, &nsIThread::Shutdown);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -559,15 +630,15 @@ nsresult
|
||||
DispatchToDBusThread(nsIRunnable* event)
|
||||
{
|
||||
nsRefPtr<nsIThread> dbusServiceThread(gDBusServiceThread);
|
||||
nsRefPtr<DBusThread> dbusThread(gDBusThread);
|
||||
nsRefPtr<DBusWatcher> dbusWatcher(gDBusWatcher);
|
||||
|
||||
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusThread.get(),
|
||||
NS_ENSURE_TRUE(dbusServiceThread.get() && dbusWatcher.get(),
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv = dbusServiceThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
dbusThread->WakeUp();
|
||||
dbusWatcher->WakeUp();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -456,39 +456,93 @@ void Sampler::UnregisterCurrentThread()
|
||||
static struct sigaction old_sigstart_signal_handler;
|
||||
const int SIGSTART = SIGUSR2;
|
||||
|
||||
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
static void freeArray(const char** array, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
free((void*) array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t readCSVArray(char* csvList, const char** buffer) {
|
||||
uint32_t count;
|
||||
char* savePtr;
|
||||
int newlinePos = strlen(csvList) - 1;
|
||||
if (csvList[newlinePos] == '\n') {
|
||||
csvList[newlinePos] = '\0';
|
||||
}
|
||||
|
||||
char* item = strtok_r(csvList, ",", &savePtr);
|
||||
for (count = 0; item; item = strtok_r(NULL, ",", &savePtr)) {
|
||||
int length = strlen(item) + 1; // Include \0
|
||||
char* newBuf = (char*) malloc(sizeof(char) * length);
|
||||
buffer[count] = newBuf;
|
||||
strncpy(newBuf, item, length);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Currently support only the env variables
|
||||
// reported in read_profiler_env
|
||||
static void ReadProfilerVars(const char* fileName, const char** features,
|
||||
uint32_t* featureCount, const char** threadNames, uint32_t* threadCount) {
|
||||
FILE* file = fopen(fileName, "r");
|
||||
const int bufferSize = 1024;
|
||||
char line[bufferSize];
|
||||
char* feature;
|
||||
char* value;
|
||||
char* savePtr;
|
||||
|
||||
if (file) {
|
||||
while (fgets(line, bufferSize, file) != NULL) {
|
||||
feature = strtok_r(line, "=", &savePtr);
|
||||
value = strtok_r(NULL, "", &savePtr);
|
||||
|
||||
if (strncmp(feature, PROFILER_MODE, bufferSize) == 0) {
|
||||
set_profiler_mode(value);
|
||||
} else if (strncmp(feature, PROFILER_INTERVAL, bufferSize) == 0) {
|
||||
set_profiler_interval(value);
|
||||
} else if (strncmp(feature, PROFILER_ENTRIES, bufferSize) == 0) {
|
||||
set_profiler_entries(value);
|
||||
} else if (strncmp(feature, PROFILER_STACK, bufferSize) == 0) {
|
||||
set_profiler_scan(value);
|
||||
} else if (strncmp(feature, PROFILER_FEATURES, bufferSize) == 0) {
|
||||
*featureCount = readCSVArray(value, features);
|
||||
} else if (strncmp(feature, "threads", bufferSize) == 0) {
|
||||
*threadCount = readCSVArray(value, threadNames);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
// XXX: Everything we do here is NOT async signal safe. We risk nasty things
|
||||
// like deadlocks but we typically only do this once so it tends to be ok.
|
||||
// See bug 909403
|
||||
const char* threadName = NULL;
|
||||
uint32_t threadCount = 0;
|
||||
char thread[256];
|
||||
|
||||
// TODO support selecting features from profiler.options
|
||||
const char* features[3] = {NULL, NULL, NULL};
|
||||
uint32_t featureCount = 0;
|
||||
features[0] = "leaf";
|
||||
featureCount++;
|
||||
features[1] = "js";
|
||||
featureCount++;
|
||||
const char* threadFeature = "threads";
|
||||
uint32_t threadCount = 0;
|
||||
|
||||
std::ifstream infile;
|
||||
infile.open("/data/local/tmp/profiler.options");
|
||||
if (infile.is_open()) {
|
||||
infile.getline(thread, 256);
|
||||
threadName = thread;
|
||||
threadCount = 1;
|
||||
features[featureCount] = threadFeature;
|
||||
featureCount++;
|
||||
printf_stderr("Profiling only %s\n", threadName);
|
||||
}
|
||||
infile.close();
|
||||
// Just allocate 10 features for now
|
||||
// FIXME: these don't really point to const chars*
|
||||
// So we free them later, but we don't want to change the const char**
|
||||
// declaration in profiler_start. Annoying but ok for now.
|
||||
const char* threadNames[10];
|
||||
const char* features[10];
|
||||
const char* profilerConfigFile = "/data/local/tmp/profiler.options";
|
||||
|
||||
ReadProfilerVars(profilerConfigFile, features, &featureCount, threadNames, &threadCount);
|
||||
MOZ_ASSERT(featureCount < 10);
|
||||
MOZ_ASSERT(threadCount < 10);
|
||||
|
||||
profiler_start(PROFILE_DEFAULT_ENTRY, 1,
|
||||
features, featureCount,
|
||||
&threadName, threadCount);
|
||||
features, featureCount,
|
||||
threadNames, threadCount);
|
||||
|
||||
freeArray(threadNames, threadCount);
|
||||
freeArray(features, featureCount);
|
||||
}
|
||||
|
||||
void OS::RegisterStartHandler()
|
||||
|
@ -46,6 +46,13 @@ int sLastFrameNumber = 0;
|
||||
int sInitCount = 0; // Each init must have a matched shutdown.
|
||||
static bool sIsProfiling = false; // is raced on
|
||||
|
||||
// env variables to control the profiler
|
||||
const char* PROFILER_MODE = "MOZ_PROFILER_MODE";
|
||||
const char* PROFILER_INTERVAL = "MOZ_PROFILER_INTERVAL";
|
||||
const char* PROFILER_ENTRIES = "MOZ_PROFILER_ENTRIES";
|
||||
const char* PROFILER_STACK = "MOZ_PROFILER_STACK_SCAN";
|
||||
const char* PROFILER_FEATURES = "MOZ_PROFILING_FEATURES";
|
||||
|
||||
/* used to keep track of the last event that we sampled during */
|
||||
unsigned int sLastSampledEventGeneration = 0;
|
||||
|
||||
@ -252,68 +259,112 @@ static inline const char* name_UnwMode(UnwMode m)
|
||||
}
|
||||
}
|
||||
|
||||
bool set_profiler_mode(const char* mode) {
|
||||
if (mode) {
|
||||
if (0 == strcmp(mode, "pseudo")) {
|
||||
sUnwindMode = UnwPSEUDO;
|
||||
return true;
|
||||
}
|
||||
else if (0 == strcmp(mode, "native") && is_native_unwinding_avail()) {
|
||||
sUnwindMode = UnwNATIVE;
|
||||
return true;
|
||||
}
|
||||
else if (0 == strcmp(mode, "combined") && is_native_unwinding_avail()) {
|
||||
sUnwindMode = UnwCOMBINED;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_interval(const char* interval) {
|
||||
if (interval) {
|
||||
errno = 0;
|
||||
long int n = strtol(interval, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 1 && n <= 1000) {
|
||||
sUnwindInterval = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_entries(const char* entries) {
|
||||
if (entries) {
|
||||
errno = 0;
|
||||
long int n = strtol(entries, (char**)NULL, 10);
|
||||
if (errno == 0 && n > 0) {
|
||||
sProfileEntries = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_scan(const char* scanCount) {
|
||||
if (scanCount) {
|
||||
errno = 0;
|
||||
long int n = strtol(scanCount, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 0 && n <= 100) {
|
||||
sUnwindStackScan = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_native_unwinding_avail() {
|
||||
# if defined(HAVE_NATIVE_UNWIND)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Read env vars at startup, so as to set sUnwindMode and sInterval.
|
||||
void read_profiler_env_vars()
|
||||
{
|
||||
bool nativeAvail = false;
|
||||
# if defined(HAVE_NATIVE_UNWIND)
|
||||
nativeAvail = true;
|
||||
# endif
|
||||
|
||||
MOZ_ASSERT(sUnwindMode == UnwINVALID);
|
||||
MOZ_ASSERT(sUnwindInterval == 0);
|
||||
MOZ_ASSERT(sProfileEntries == 0);
|
||||
bool nativeAvail = is_native_unwinding_avail();
|
||||
|
||||
/* Set defaults */
|
||||
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindInterval = 0; /* We'll have to look elsewhere */
|
||||
sProfileEntries = 0;
|
||||
|
||||
const char* strM = PR_GetEnv("MOZ_PROFILER_MODE");
|
||||
const char* strI = PR_GetEnv("MOZ_PROFILER_INTERVAL");
|
||||
const char* strE = PR_GetEnv("MOZ_PROFILER_ENTRIES");
|
||||
const char* strF = PR_GetEnv("MOZ_PROFILER_STACK_SCAN");
|
||||
const char* stackMode = PR_GetEnv(PROFILER_MODE);
|
||||
const char* interval = PR_GetEnv(PROFILER_INTERVAL);
|
||||
const char* entries = PR_GetEnv(PROFILER_ENTRIES);
|
||||
const char* scanCount = PR_GetEnv(PROFILER_STACK);
|
||||
|
||||
if (strM) {
|
||||
if (0 == strcmp(strM, "pseudo"))
|
||||
sUnwindMode = UnwPSEUDO;
|
||||
else if (0 == strcmp(strM, "native") && nativeAvail)
|
||||
sUnwindMode = UnwNATIVE;
|
||||
else if (0 == strcmp(strM, "combined") && nativeAvail)
|
||||
sUnwindMode = UnwCOMBINED;
|
||||
else goto usage;
|
||||
if (!set_profiler_mode(stackMode) ||
|
||||
!set_profiler_interval(interval) ||
|
||||
!set_profiler_entries(entries) ||
|
||||
!set_profiler_scan(scanCount)) {
|
||||
profiler_usage();
|
||||
} else {
|
||||
LOG( "SPS:");
|
||||
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
|
||||
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
|
||||
(int)sUnwindInterval);
|
||||
LOGF("SPS: Entry store size = %d (zero means \"platform default\")",
|
||||
(int)sProfileEntries);
|
||||
LOGF("SPS: UnwindStackScan = %d (max dubious frames per unwind).",
|
||||
(int)sUnwindStackScan);
|
||||
LOG( "SPS: Use env var MOZ_PROFILER_MODE=help for further information.");
|
||||
LOG( "SPS:");
|
||||
}
|
||||
}
|
||||
|
||||
if (strI) {
|
||||
errno = 0;
|
||||
long int n = strtol(strI, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 1 && n <= 1000) {
|
||||
sUnwindInterval = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
if (strE) {
|
||||
errno = 0;
|
||||
long int n = strtol(strE, (char**)NULL, 10);
|
||||
if (errno == 0 && n > 0) {
|
||||
sProfileEntries = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
if (strF) {
|
||||
errno = 0;
|
||||
long int n = strtol(strF, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 0 && n <= 100) {
|
||||
sUnwindStackScan = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
usage:
|
||||
void profiler_usage() {
|
||||
LOG( "SPS: ");
|
||||
LOG( "SPS: Environment variable usage:");
|
||||
LOG( "SPS: ");
|
||||
@ -339,15 +390,15 @@ void read_profiler_env_vars()
|
||||
LOG( "SPS: Needs to be set to use Breakpad-based unwinding.");
|
||||
LOG( "SPS: ");
|
||||
LOGF("SPS: This platform %s native unwinding.",
|
||||
nativeAvail ? "supports" : "does not support");
|
||||
is_native_unwinding_avail() ? "supports" : "does not support");
|
||||
LOG( "SPS: ");
|
||||
|
||||
/* Re-set defaults */
|
||||
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindMode = is_native_unwinding_avail() ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindInterval = 0; /* We'll have to look elsewhere */
|
||||
sProfileEntries = 0;
|
||||
sUnwindStackScan = 0;
|
||||
|
||||
out:
|
||||
LOG( "SPS:");
|
||||
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
|
||||
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
|
||||
|
@ -240,7 +240,22 @@ class Thread {
|
||||
|
||||
/* Some values extracted at startup from environment variables, that
|
||||
control the behaviour of the breakpad unwinder. */
|
||||
extern const char* PROFILER_MODE;
|
||||
extern const char* PROFILER_INTERVAL;
|
||||
extern const char* PROFILER_ENTRIES;
|
||||
extern const char* PROFILER_STACK;
|
||||
extern const char* PROFILER_FEATURES;
|
||||
|
||||
void read_profiler_env_vars();
|
||||
void profiler_usage();
|
||||
|
||||
// Helper methods to expose modifying profiler behavior
|
||||
bool set_profiler_mode(const char*);
|
||||
bool set_profiler_interval(const char*);
|
||||
bool set_profiler_entries(const char*);
|
||||
bool set_profiler_scan(const char*);
|
||||
bool is_native_unwinding_avail();
|
||||
|
||||
typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode;
|
||||
extern UnwMode sUnwindMode; /* what mode? */
|
||||
extern int sUnwindInterval; /* in milliseconds */
|
||||
|
Loading…
Reference in New Issue
Block a user