Skip to content

Commit 5e9ad21

Browse files
Michael Fabian Dirksjp9000
authored andcommitted
Use CEF multi-threaded handler and use C++11
This also enables CEF sandboxing, which should help users be more secure against harmful ads and sites. Closes #58
1 parent 1f57e19 commit 5e9ad21

File tree

2 files changed

+97
-131
lines changed

2 files changed

+97
-131
lines changed

obs-browser/browser-manager-base.cpp

Lines changed: 79 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "browser-render-handler.hpp"
1010
#include "browser-load-handler.hpp"
1111
#include "browser-obs-bridge-base.hpp"
12+
#include <chrono>
13+
#include <thread>
1214

1315
BrowserManager::BrowserManager()
1416
: pimpl(new BrowserManager::Impl())
@@ -104,25 +106,31 @@ void BrowserManager::DispatchJSEvent(const char *eventName, const char *jsonStri
104106
pimpl->DispatchJSEvent(eventName, jsonString);
105107
}
106108

107-
BrowserManager::Impl::Impl()
109+
std::string getBootstrap()
108110
{
109-
os_event_init(&dispatchEvent, OS_EVENT_TYPE_AUTO);
110-
pthread_mutex_init(&dispatchLock, nullptr);
111+
std::string modulePath(BrowserManager::Instance()->GetModulePath());
112+
std::string parentPath(modulePath.substr(0,
113+
modulePath.find_last_of('/') + 1));
114+
#ifdef _WIN32
115+
return parentPath + "/cef-bootstrap.exe";
116+
#else
117+
return parentPath + "/cef-bootstrap";
118+
#endif
111119
}
112120

113-
BrowserManager::Impl::~Impl()
114-
{
115-
os_event_destroy(dispatchEvent);
116-
pthread_mutex_destroy(&dispatchLock);
117-
}
121+
//////////////////////////////////////////////////////////////////////////
122+
// BrowserManager::Impl
123+
BrowserManager::Impl::Impl() {}
124+
125+
BrowserManager::Impl::~Impl() {}
118126

119127
int BrowserManager::Impl::CreateBrowser(
120128
const BrowserSettings &browserSettings,
121129
const std::shared_ptr<BrowserListener> &browserListener)
122130
{
123131
int browserIdentifier = 0;
124-
os_event_t *createdEvent;
125-
os_event_init(&createdEvent, OS_EVENT_TYPE_AUTO);
132+
std::mutex createMutex;
133+
std::condition_variable createEvent;
126134

127135
BrowserOBSBridge *browserOBSBridge = new BrowserOBSBridgeBase();
128136

@@ -157,11 +165,11 @@ int BrowserManager::Impl::CreateBrowser(
157165
browserIdentifier = browser->GetIdentifier();
158166
browserMap[browserIdentifier] = browser;
159167
}
160-
os_event_signal(createdEvent);
168+
createEvent.notify_all();
161169
}));
162170

163-
os_event_wait(createdEvent);
164-
os_event_destroy(createdEvent);
171+
std::unique_lock<std::mutex> createLock(createMutex);
172+
createEvent.wait(createLock);
165173
return browserIdentifier;
166174
}
167175

@@ -170,15 +178,14 @@ BrowserManager::Impl::DestroyBrowser(int browserIdentifier)
170178
{
171179
if (browserMap.count(browserIdentifier) > 0) {
172180
CefRefPtr<CefBrowser> browser = browserMap[browserIdentifier];
173-
os_event_t *closeEvent;
174-
os_event_init(&closeEvent, OS_EVENT_TYPE_AUTO);
175-
CefPostTask(TID_UI, BrowserTask::newTask([&, browser]
181+
std::mutex closeMutex;
182+
std::condition_variable closeEvent;
183+
CefPostTask(TID_UI, BrowserTask::newTask([&, browser]
176184
{
177185
browser->GetHost()->CloseBrowser(true);
178-
os_event_signal(closeEvent);
186+
closeEvent.notify_all();
179187
}));
180-
os_event_wait(closeEvent);
181-
os_event_destroy(closeEvent);
188+
closeEvent.wait(std::unique_lock<std::mutex>(closeMutex));
182189
browserMap.erase(browserIdentifier);
183190
}
184191
}
@@ -198,14 +205,13 @@ void BrowserManager::Impl::ExecuteOnBrowser(int browserIdentifier,
198205
f(browser);
199206
}));
200207
} else {
201-
os_event_t *finishedEvent;
202-
os_event_init(&finishedEvent, OS_EVENT_TYPE_AUTO);
208+
std::mutex finishedMutex;
209+
std::condition_variable finishedEvent;
203210
CefPostTask(TID_UI, BrowserTask::newTask([&] {
204211
f(browser);
205-
os_event_signal(finishedEvent);
212+
finishedEvent.notify_all();
206213
}));
207-
os_event_wait(finishedEvent);
208-
os_event_destroy(finishedEvent);
214+
finishedEvent.wait(std::unique_lock<std::mutex>(finishedMutex));
209215
}
210216
}
211217
}
@@ -221,14 +227,13 @@ void BrowserManager::Impl::ExecuteOnAllBrowsers(
221227
f(browser);
222228
}));
223229
} else {
224-
os_event_t *finishedEvent;
225-
os_event_init(&finishedEvent, OS_EVENT_TYPE_AUTO);
230+
std::mutex finishedMutex;
231+
std::condition_variable finishedEvent;
226232
CefPostTask(TID_UI, BrowserTask::newTask([&] {
227233
f(browser);
228-
os_event_signal(finishedEvent);
234+
finishedEvent.notify_all();
229235
}));
230-
os_event_wait(finishedEvent);
231-
os_event_destroy(finishedEvent);
236+
finishedEvent.wait(std::unique_lock<std::mutex>(finishedMutex));
232237
}
233238
}
234239
}
@@ -363,112 +368,69 @@ void BrowserManager::Impl::DispatchJSEvent(const char *eventName, const char *js
363368
});
364369
}
365370

366-
void
367-
BrowserManager::Impl::Startup()
371+
void BrowserManager::Impl::Startup()
368372
{
369-
pthread_mutex_lock(&dispatchLock);
370-
int ret = pthread_create(&managerThread, nullptr,
371-
browserManagerEntry, this);
372-
373-
if (ret != 0) {
374-
blog(LOG_ERROR,
375-
"BrowserManager: failed to create browser "
376-
"manager thread.");
377-
threadAlive = false;
378-
}
379-
else {
380-
threadAlive = true;
381-
}
382-
pthread_mutex_unlock(&dispatchLock);
383-
384-
return;
385-
}
373+
// Initialize CEF
374+
CefMainArgs mainArgs;
375+
CefSettings settings;
376+
settings.log_severity = LOGSEVERITY_VERBOSE;
377+
settings.windowless_rendering_enabled = true;
378+
settings.no_sandbox = false;
379+
settings.multi_threaded_message_loop = true;
380+
CefString(&settings.cache_path).FromASCII(obs_module_config_path(""));
381+
CefString(&settings.browser_subprocess_path) = getBootstrap();
382+
CefRefPtr<BrowserApp> app(new BrowserApp());
383+
CefExecuteProcess(mainArgs, app, nullptr);
384+
CefInitialize(mainArgs, settings, app, nullptr);
385+
CefRegisterSchemeHandlerFactory("http", "absolute", new BrowserSchemeHandlerFactory());
386386

387-
void BrowserManager::Impl::Shutdown()
388-
{
389-
os_event_t *shutdown_event;
390-
os_event_init(&shutdown_event, OS_EVENT_TYPE_AUTO);
391-
392-
// post the task
393-
CefPostTask(TID_UI, BrowserTask::newTask([] {
394-
CefQuitMessageLoop();
395-
}));
387+
// Initialize event queue.
388+
{
389+
std::lock_guard<std::mutex> lock(events.mutex);
390+
events.bQuit = false;
391+
events.thread = std::thread(QueueThreadMain, this);
392+
}
396393

397-
// this event will then get processed and shut down the dispatcher loop
398-
PushEvent([this, shutdown_event] {
399-
threadAlive = false;
400-
os_event_signal(shutdown_event);
401-
});
402394

403-
os_event_wait(shutdown_event);
404-
os_event_destroy(shutdown_event);
405395
return;
406396
}
407397

408-
void *BrowserManager::Impl::browserManagerEntry(void* threadArgument)
398+
void BrowserManager::Impl::Shutdown()
409399
{
410-
BrowserManager::Impl *browserManager =
411-
static_cast<BrowserManager::Impl *>(threadArgument);
412-
browserManager->BrowserManagerEntry();
413-
return nullptr;
400+
// Quit Event Thread
401+
events.bQuit = true;
402+
events.condvar.notify_all();
403+
events.thread.join();
404+
405+
// Shut down CEF
406+
CefShutdown();
407+
return;
414408
}
415409

416410
void BrowserManager::Impl::PushEvent(std::function<void()> event)
417411
{
418-
pthread_mutex_lock(&dispatchLock);
419-
queue.push_back(event);
420-
pthread_mutex_unlock(&dispatchLock);
421-
os_event_signal(dispatchEvent);
412+
std::lock_guard<std::mutex> lock(events.mutex);
413+
events.queue.push(event);
414+
events.condvar.notify_one();
422415
}
423416

424-
std::string getBootstrap()
417+
void BrowserManager::Impl::QueueThreadMain(void* data)
425418
{
426-
std::string modulePath(BrowserManager::Instance()->GetModulePath());
427-
std::string parentPath(modulePath.substr(0,
428-
modulePath.find_last_of('/') + 1));
429-
#ifdef _WIN32
430-
return parentPath + "/cef-bootstrap.exe";
431-
#else
432-
return parentPath + "/cef-bootstrap";
433-
#endif
419+
auto obj = static_cast<BrowserManager::Impl*>(data);
420+
obj->QueueThreadLocalMain();
434421
}
435422

436-
void BrowserManager::Impl::BrowserManagerEntry()
437-
{
438-
std::string bootstrapPath = getBootstrap();
439-
bool thread_exit = false;
440-
PushEvent([] {
441-
CefMainArgs mainArgs;
442-
CefSettings settings;
443-
settings.log_severity = LOGSEVERITY_VERBOSE;
444-
settings.windowless_rendering_enabled = true;
445-
settings.no_sandbox = true;
446-
CefString(&settings.cache_path).FromASCII(obs_module_config_path(""));
447-
CefString(&settings.browser_subprocess_path) = getBootstrap();
448-
CefRefPtr<BrowserApp> app(new BrowserApp());
449-
CefExecuteProcess(mainArgs, app, nullptr);
450-
CefInitialize(mainArgs, settings, app, nullptr);
451-
CefRegisterSchemeHandlerFactory("http", "absolute", new BrowserSchemeHandlerFactory());
452-
CefRunMessageLoop();
453-
CefShutdown();
454-
});
455-
456-
while (true) {
457-
458-
if (os_event_timedwait(dispatchEvent, 10) != ETIMEDOUT) {
459-
pthread_mutex_lock(&dispatchLock);
460-
while (!queue.empty()) {
461-
auto event = queue[0];
462-
event();
463-
queue.erase(queue.begin());
464-
}
465-
thread_exit = !threadAlive;
466-
pthread_mutex_unlock(&dispatchLock);
467-
if (thread_exit) {
468-
return;
469-
}
423+
void BrowserManager::Impl::QueueThreadLocalMain()
424+
{
425+
std::unique_lock<std::mutex> ulock(events.mutex);
426+
do {
427+
events.condvar.wait(ulock);
428+
while (events.queue.size() > 0) {
429+
auto v = events.queue.front();
430+
v();
431+
events.queue.pop();
470432
}
471-
}
433+
} while (events.bQuit == false);
472434
}
473435

474436
static BrowserManager *instance;

obs-browser/browser-manager-base.hpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
#include <functional>
1010
#include <util/threading.h>
1111

12+
#include <thread>
13+
#include <mutex>
14+
#include <condition_variable>
15+
#include <queue>
16+
1217
#include "browser-manager.hpp"
1318

1419
class BrowserManager::Impl
@@ -18,14 +23,6 @@ class BrowserManager::Impl
1823
Impl();
1924
~Impl();
2025

21-
private:
22-
23-
static void *browserManagerEntry(void* threadArguments);
24-
void BrowserManagerEntry();
25-
26-
27-
public:
28-
2926
void Startup();
3027
void Shutdown();
3128

@@ -71,12 +68,19 @@ class BrowserManager::Impl
7168
bool async = false);
7269

7370
private:
74-
bool threadAlive;
75-
os_event_t *dispatchEvent;
76-
pthread_t managerThread;
77-
pthread_mutex_t dispatchLock;
78-
7971
std::map<int, std::shared_ptr<BrowserListener>> listenerMap;
8072
std::map<int, CefRefPtr<CefBrowser> > browserMap;
81-
std::vector<std::function<void()>> queue;
73+
74+
// Holds Queue related Information
75+
struct {
76+
std::thread thread;
77+
std::mutex mutex;
78+
std::condition_variable condvar;
79+
std::queue<std::function<void()>> queue;
80+
81+
bool bQuit = false;
82+
} events;
83+
static void QueueThreadMain(void*);
84+
void QueueThreadLocalMain();
85+
8286
};

0 commit comments

Comments
 (0)