mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b3753bb742
Currently DBusWatcher registers read and write watchers on the I/O thread unconditionally. Thus for read-only DBusWatch structures, the write watcher on the I/O thread generates a significant amount of CPU overhead by constantly reporting success via calls to OnFileCanWriteWithoutBlocking. This patch changes DBusWatcher to respect the status flags of supplied DBusWatch structures. It will only poll for read or write status if the DBus watch has the corresponding flag set. DBus keeps track of these flags and calls the toggle callback when it needs to wait on a certain DBusWatch.
327 lines
7.6 KiB
C++
327 lines
7.6 KiB
C++
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/*
|
|
* Copyright 2009, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* NOTE: Due to being based on the dbus compatibility layer for
|
|
* android's bluetooth implementation, this file is licensed under the
|
|
* apache license instead of MPL.
|
|
*
|
|
*/
|
|
|
|
#include "DBusThread.h"
|
|
#include "RawDBusConnection.h"
|
|
#include "DBusUtils.h"
|
|
|
|
#include <dbus/dbus.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/select.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <poll.h>
|
|
|
|
#include <list>
|
|
|
|
#include "base/eintr_wrapper.h"
|
|
#include "base/message_loop.h"
|
|
#include "nsTArray.h"
|
|
#include "nsDataHashtable.h"
|
|
#include "mozilla/SyncRunnable.h"
|
|
#include "mozilla/NullPtr.h"
|
|
#include "mozilla/StaticPtr.h"
|
|
#include "mozilla/Monitor.h"
|
|
#include "mozilla/FileUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsIThread.h"
|
|
#include "nsXULAppAPI.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsCOMPtr.h"
|
|
|
|
#undef CHROMIUM_LOG
|
|
#if defined(MOZ_WIDGET_GONK)
|
|
#include <android/log.h>
|
|
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
|
|
#else
|
|
#define BTDEBUG true
|
|
#define CHROMIUM_LOG(args...) if (BTDEBUG) printf(args);
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
class DBusWatcher : public MessageLoopForIO::Watcher
|
|
{
|
|
public:
|
|
DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
|
|
: mConnection(aConnection),
|
|
mWatch(aWatch)
|
|
{
|
|
MOZ_ASSERT(mConnection);
|
|
MOZ_ASSERT(mWatch);
|
|
}
|
|
|
|
~DBusWatcher()
|
|
{ }
|
|
|
|
void StartWatching();
|
|
void StopWatching();
|
|
|
|
static void FreeFunction(void* aData);
|
|
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
|
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
|
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
|
|
|
RawDBusConnection* GetConnection();
|
|
|
|
private:
|
|
void OnFileCanReadWithoutBlocking(int aFd);
|
|
void OnFileCanWriteWithoutBlocking(int aFd);
|
|
|
|
// Read watcher for libevent. Only to be accessed on IO Thread.
|
|
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
|
|
|
// Write watcher for libevent. Only to be accessed on IO Thread.
|
|
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
|
|
|
// DBus structures
|
|
RawDBusConnection* mConnection;
|
|
DBusWatch* mWatch;
|
|
};
|
|
|
|
RawDBusConnection*
|
|
DBusWatcher::GetConnection()
|
|
{
|
|
return mConnection;
|
|
}
|
|
|
|
void DBusWatcher::StartWatching()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(mWatch);
|
|
|
|
int fd = dbus_watch_get_unix_fd(mWatch);
|
|
|
|
MessageLoopForIO* ioLoop = MessageLoopForIO::current();
|
|
|
|
unsigned int flags = dbus_watch_get_flags(mWatch);
|
|
|
|
if (flags & DBUS_WATCH_READABLE) {
|
|
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
|
&mReadWatcher, this);
|
|
}
|
|
if (flags & DBUS_WATCH_WRITABLE) {
|
|
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
|
&mWriteWatcher, this);
|
|
}
|
|
}
|
|
|
|
void DBusWatcher::StopWatching()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
unsigned int flags = dbus_watch_get_flags(mWatch);
|
|
|
|
if (flags & DBUS_WATCH_READABLE) {
|
|
mReadWatcher.StopWatchingFileDescriptor();
|
|
}
|
|
if (flags & DBUS_WATCH_WRITABLE) {
|
|
mWriteWatcher.StopWatchingFileDescriptor();
|
|
}
|
|
}
|
|
|
|
// DBus utility functions, used as function pointers in DBus setup
|
|
|
|
void
|
|
DBusWatcher::FreeFunction(void* aData)
|
|
{
|
|
delete static_cast<DBusWatcher*>(aData);
|
|
}
|
|
|
|
dbus_bool_t
|
|
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
|
|
|
|
DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
|
|
dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
|
|
|
|
if (dbus_watch_get_enabled(aWatch)) {
|
|
dbusWatcher->StartWatching();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
DBusWatcher* dbusWatcher =
|
|
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
|
dbusWatcher->StopWatching();
|
|
}
|
|
|
|
void
|
|
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
DBusWatcher* dbusWatcher =
|
|
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
|
|
|
if (dbus_watch_get_enabled(aWatch)) {
|
|
dbusWatcher->StartWatching();
|
|
} else {
|
|
dbusWatcher->StopWatching();
|
|
}
|
|
}
|
|
|
|
void
|
|
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
|
|
|
|
DBusDispatchStatus dbusDispatchStatus;
|
|
do {
|
|
dbusDispatchStatus =
|
|
dbus_connection_dispatch(mConnection->GetConnection());
|
|
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
|
}
|
|
|
|
void
|
|
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
|
|
}
|
|
|
|
class WatchDBusConnectionTask : public Task
|
|
{
|
|
public:
|
|
WatchDBusConnectionTask(RawDBusConnection* aConnection)
|
|
: mConnection(aConnection)
|
|
{
|
|
MOZ_ASSERT(mConnection);
|
|
}
|
|
|
|
void Run()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
dbus_bool_t success =
|
|
dbus_connection_set_watch_functions(mConnection->GetConnection(),
|
|
DBusWatcher::AddWatchFunction,
|
|
DBusWatcher::RemoveWatchFunction,
|
|
DBusWatcher::ToggleWatchFunction,
|
|
mConnection, nullptr);
|
|
NS_ENSURE_TRUE_VOID(success == TRUE);
|
|
}
|
|
|
|
private:
|
|
RawDBusConnection* mConnection;
|
|
};
|
|
|
|
class DeleteDBusConnectionTask : public Task
|
|
{
|
|
public:
|
|
DeleteDBusConnectionTask(RawDBusConnection* aConnection)
|
|
: mConnection(aConnection)
|
|
{
|
|
MOZ_ASSERT(mConnection);
|
|
}
|
|
|
|
void Run()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
// This command closes the DBus connection and all instances of
|
|
// DBusWatch will be removed and free'd.
|
|
delete mConnection;
|
|
}
|
|
|
|
private:
|
|
RawDBusConnection* mConnection;
|
|
};
|
|
|
|
// Startup/Shutdown utility functions
|
|
|
|
static RawDBusConnection* gDBusConnection;
|
|
|
|
bool
|
|
StartDBus()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
NS_ENSURE_TRUE(!gDBusConnection, true);
|
|
|
|
RawDBusConnection* connection = new RawDBusConnection();
|
|
nsresult rv = connection->EstablishDBusConnection();
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
|
new WatchDBusConnectionTask(connection));
|
|
|
|
gDBusConnection = connection;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
StopDBus()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
NS_ENSURE_TRUE(gDBusConnection, true);
|
|
|
|
RawDBusConnection* connection = gDBusConnection;
|
|
gDBusConnection = nullptr;
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
|
new DeleteDBusConnectionTask(connection));
|
|
|
|
return true;
|
|
}
|
|
|
|
nsresult
|
|
DispatchToDBusThread(Task* task)
|
|
{
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, task);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
RawDBusConnection*
|
|
GetDBusConnection()
|
|
{
|
|
NS_ENSURE_TRUE(gDBusConnection, nullptr);
|
|
|
|
return gDBusConnection;
|
|
}
|
|
|
|
}
|
|
}
|