mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
f14c38867f
This patch converts DBusWatcher to run on the I/O thread. When a caller starts DBus, StartDBus creates a new connection and adds it to the I/O thread's poll loop. DBusWatchers are created and removed automatically by the DBus libary. The I/O thread provides all features of the DBus thread. So most of the existing code has been removed or rewritten. The former includes the control socket and the DBus thread, the latter is in the DBusWatcher code.
314 lines
7.3 KiB
C++
314 lines
7.3 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 LOG
|
|
#if defined(MOZ_WIDGET_GONK)
|
|
#include <android/log.h>
|
|
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
|
|
#else
|
|
#define BTDEBUG true
|
|
#define 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();
|
|
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
|
&mReadWatcher, this);
|
|
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
|
&mWriteWatcher, this);
|
|
}
|
|
|
|
void DBusWatcher::StopWatching()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
mReadWatcher.StopWatchingFileDescriptor();
|
|
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;
|
|
}
|
|
|
|
}
|
|
}
|