Share ScreenDrawerLockPosix implementation

This change renames ScreenDrawerLockLinux into ScreenDrawerLockPosix and shares
it with Mac OSX.

Bug: webrtc:7950
Change-Id: Ib141781d2c35bfda0d6f9458fff235adbb643280
Reviewed-on: https://chromium-review.googlesource.com/607688
Commit-Queue: Zijie He <zijiehe@chromium.org>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#19393}
This commit is contained in:
Zijie He 2017-08-16 14:56:42 -07:00 committed by Commit Bot
parent 53959fcc2b
commit 825f65e9d2
6 changed files with 204 additions and 30 deletions

View File

@ -127,6 +127,8 @@ if (rtc_include_tests) {
"screen_drawer.cc",
"screen_drawer.h",
"screen_drawer_linux.cc",
"screen_drawer_lock_posix.cc",
"screen_drawer_lock_posix.h",
"screen_drawer_mac.cc",
"screen_drawer_win.cc",
]

View File

@ -8,47 +8,22 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <string.h>
#include <X11/Xlib.h>
#include <memory>
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include "webrtc/modules/desktop_capture/screen_drawer_lock_posix.h"
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/system_wrappers/include/sleep.h"
namespace webrtc {
namespace {
static constexpr char kSemaphoreName[] =
"/global-screen-drawer-linux-54fe5552-8047-11e6-a725-3f429a5b4fb4";
class ScreenDrawerLockLinux : public ScreenDrawerLock {
public:
ScreenDrawerLockLinux();
~ScreenDrawerLockLinux() override;
private:
sem_t* semaphore_;
};
ScreenDrawerLockLinux::ScreenDrawerLockLinux() {
semaphore_ =
sem_open(kSemaphoreName, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1);
sem_wait(semaphore_);
}
ScreenDrawerLockLinux::~ScreenDrawerLockLinux() {
sem_post(semaphore_);
sem_close(semaphore_);
// sem_unlink(kSemaphoreName);
}
// A ScreenDrawer implementation for X11.
class ScreenDrawerLinux : public ScreenDrawer {
public:
@ -187,13 +162,13 @@ void ScreenDrawerLinux::BringToFront() {
// static
std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
return std::unique_ptr<ScreenDrawerLock>(new ScreenDrawerLockLinux());
return rtc::MakeUnique<ScreenDrawerLockPosix>();
}
// static
std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
if (SharedXDisplay::CreateDefault().get()) {
return std::unique_ptr<ScreenDrawer>(new ScreenDrawerLinux());
return rtc::MakeUnique<ScreenDrawerLinux>();
}
return nullptr;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/desktop_capture/screen_drawer_lock_posix.h"
#include <fcntl.h>
#include <sys/stat.h>
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/logging.h"
namespace webrtc {
namespace {
// A uuid as the name of semaphore.
static constexpr char kSemaphoreName[] = "GSDL54fe5552804711e6a7253f429a";
} // namespace
ScreenDrawerLockPosix::ScreenDrawerLockPosix()
: ScreenDrawerLockPosix(kSemaphoreName) {}
ScreenDrawerLockPosix::ScreenDrawerLockPosix(const char* name) {
semaphore_ = sem_open(name, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1);
if (semaphore_ == SEM_FAILED) {
LOG_ERRNO(LS_ERROR) << "Failed to create named semaphore with " << name;
RTC_NOTREACHED();
}
sem_wait(semaphore_);
}
ScreenDrawerLockPosix::~ScreenDrawerLockPosix() {
if (semaphore_ == SEM_FAILED) {
return;
}
sem_post(semaphore_);
sem_close(semaphore_);
// sem_unlink a named semaphore won't wait until other clients to release the
// sem_t. So if a new process starts, it will sem_open a different kernel
// object with the same name and eventually breaks the cross-process lock.
}
// static
void ScreenDrawerLockPosix::Unlink(const char* name) {
sem_unlink(name);
}
} // namespace webrtc

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_LOCK_POSIX_H_
#define WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_LOCK_POSIX_H_
#include <semaphore.h>
#include "webrtc/modules/desktop_capture/screen_drawer.h"
namespace webrtc {
class ScreenDrawerLockPosix final : public ScreenDrawerLock {
public:
ScreenDrawerLockPosix();
// Provides a name other than the default one for test only.
explicit ScreenDrawerLockPosix(const char* name);
~ScreenDrawerLockPosix() override;
// Unlinks the named semaphore actively. This will remove the sem_t object in
// the system and allow others to create a different sem_t object with the
// same/ name.
static void Unlink(const char* name);
private:
sem_t* semaphore_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_DRAWER_LOCK_POSIX_H_

View File

@ -11,12 +11,14 @@
// TODO(zijiehe): Implement ScreenDrawerMac
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include "webrtc/modules/desktop_capture/screen_drawer_lock_posix.h"
#include "webrtc/rtc_base/ptr_util.h"
namespace webrtc {
// static
std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
return nullptr;
return rtc::MakeUnique<ScreenDrawerLockPosix>();
}
// static

View File

@ -10,16 +10,98 @@
#include "webrtc/modules/desktop_capture/screen_drawer.h"
#include <atomic>
#include <stdint.h>
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/function_view.h"
#include "webrtc/rtc_base/logging.h"
#include "webrtc/rtc_base/random.h"
#include "webrtc/rtc_base/platform_thread.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/test/gtest.h"
#if defined(WEBRTC_POSIX)
#include "webrtc/modules/desktop_capture/screen_drawer_lock_posix.h"
#endif
namespace webrtc {
namespace {
void TestScreenDrawerLock(
rtc::FunctionView<std::unique_ptr<ScreenDrawerLock>()> ctor) {
constexpr int kLockDurationMs = 100;
RTC_DCHECK(ctor);
std::atomic<bool> created(false);
std::atomic<bool> ready(false);
class Task {
public:
Task(std::atomic<bool>* created,
const std::atomic<bool>& ready,
rtc::FunctionView<std::unique_ptr<ScreenDrawerLock>()> ctor)
: created_(created),
ready_(ready),
ctor_(ctor) {}
~Task() = default;
static void RunTask(void* me) {
Task* task = static_cast<Task*>(me);
std::unique_ptr<ScreenDrawerLock> lock = task->ctor_();
ASSERT_TRUE(!!lock);
task->created_->store(true);
// Wait for the main thread to get the signal of created_.
while (!task->ready_.load()) {
SleepMs(1);
}
// At this point, main thread should begin to create a second lock. Though
// it's still possible the second lock won't be created before the
// following sleep has been finished, the possibility will be
// significantly reduced.
const int64_t current_ms = rtc::TimeMillis();
// SleepMs() may return early. See
// https://cs.chromium.org/chromium/src/third_party/webrtc/system_wrappers/include/sleep.h?rcl=4a604c80cecce18aff6fc5e16296d04675312d83&l=20
// But we need to ensure at least 100 ms has been passed before unlocking
// |lock|.
while (rtc::TimeMillis() - current_ms < kLockDurationMs) {
SleepMs(kLockDurationMs - (rtc::TimeMillis() - current_ms));
}
}
private:
std::atomic<bool>* const created_;
const std::atomic<bool>& ready_;
const rtc::FunctionView<std::unique_ptr<ScreenDrawerLock>()> ctor_;
} task(&created, ready, ctor);
rtc::PlatformThread lock_thread(&Task::RunTask, &task, "lock_thread");
lock_thread.Start();
// Wait for the first lock in Task::RunTask() to be created.
// TODO(zijiehe): Find a better solution to wait for the creation of the first
// lock. See https://chromium-review.googlesource.com/c/607688/13/webrtc/modules/desktop_capture/screen_drawer_unittest.cc
while (!created.load()) {
SleepMs(1);
}
const int64_t start_ms = rtc::TimeMillis();
ready.store(true);
// This is unlikely to fail, but just in case current thread is too laggy and
// cause the SleepMs() in RunTask() to finish before we creating another lock.
ASSERT_GT(kLockDurationMs, rtc::TimeMillis() - start_ms);
ctor();
ASSERT_LE(kLockDurationMs, rtc::TimeMillis() - start_ms);
lock_thread.Stop();
}
} // namespace
// These are a set of manual test cases, as we do not have an automatical way to
// detect whether a ScreenDrawer on a certain platform works well without
// ScreenCapturer(s). So you may execute these test cases with
@ -57,4 +139,21 @@ TEST(ScreenDrawerTest, DISABLED_DrawRectangles) {
SleepMs(10000);
}
TEST(ScreenDrawerTest, TwoScreenDrawerLocks) {
#if defined(WEBRTC_POSIX)
// ScreenDrawerLockPosix won't be able to unlink the named semaphore. So use a
// different semaphore name here to avoid deadlock.
const char* semaphore_name = "GSDL8784541a812011e788ff67427b";
ScreenDrawerLockPosix::Unlink(semaphore_name);
TestScreenDrawerLock([semaphore_name]() {
return rtc::MakeUnique<ScreenDrawerLockPosix>(semaphore_name);
});
#elif defined(WEBRTC_WIN)
TestScreenDrawerLock([]() {
return ScreenDrawerLock::Create();
});
#endif
}
} // namespace webrtc