2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/vm-protect.h"
21 #include "hphp/runtime/base/rds.h"
22 #include "hphp/runtime/vm/vm-regs.h"
24 #include <folly/portability/SysMman.h>
25 #include <folly/portability/Unistd.h>
27 namespace HPHP
{ namespace jit
{
32 std::atomic
<void*> s_fakeRdsBase
{nullptr};
33 __thread
const VMProtect
* tl_active_prot
{nullptr};
36 if (UNLIKELY(!s_fakeRdsBase
.load(std::memory_order_acquire
))) {
37 std::lock_guard
<std::mutex
> guard(s_lock
);
38 if (!s_fakeRdsBase
.load(std::memory_order_relaxed
)) {
39 rds::tl_base
= nullptr;
40 rds::threadInit(false /* shouldRegister */);
42 // The current thread may attempt to read the Gen numbers of the normal
43 // portion of rds. These will all be invalid. No writes to non-persistent
44 // rds should occur while this guard is active. Leave the first page
45 // unprotected since surprise flags live there and we still do things in
46 // the jit that could write to them (like allocating request memory).
48 static_cast<char*>(rds::tl_base
) + sysconf(_SC_PAGESIZE
);
49 auto const protlen
= rds::persistentSection().begin() - base
;
51 auto const result
= mprotect(base
, protlen
, PROT_READ
);
52 always_assert(result
== 0);
54 s_fakeRdsBase
.store(rds::tl_base
, std::memory_order_release
);
57 rds::tl_base
= s_fakeRdsBase
.load(std::memory_order_acquire
);
59 tl_regState
= VMRegState::DIRTY
;
60 VMProtect::is_protected
= true;
63 void unprotect(void* base
, VMRegState state
) {
64 assertx(rds::tl_base
== s_fakeRdsBase
.load(std::memory_order_relaxed
));
67 VMProtect::is_protected
= false;
72 __thread
bool VMProtect::is_protected
{false};
74 VMProtect::VMProtect()
75 : m_oldBase(rds::tl_base
)
76 , m_oldState(tl_regState
)
78 if (is_protected
) return;
80 assertx(tl_active_prot
== nullptr);
81 tl_active_prot
= this;
85 VMProtect::~VMProtect() {
86 if (tl_active_prot
!= this) return;
88 unprotect(m_oldBase
, m_oldState
);
89 tl_active_prot
= nullptr;
92 VMProtect::Pause::Pause() {
93 if (auto const prot
= tl_active_prot
) {
94 unprotect(prot
->m_oldBase
, prot
->m_oldState
);
98 VMProtect::Pause::~Pause() {
99 if (tl_active_prot
) protect();