244d4da93a
Makes things more consistent, at least within this directory.
149 linhas
4.7 KiB
C++
149 linhas
4.7 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
#include "hphp/runtime/vm/jit/write-lease.h"
|
|
#include "hphp/util/timer.h"
|
|
#include "hphp/runtime/vm/bytecode.h"
|
|
#include "hphp/runtime/vm/jit/translator.h"
|
|
|
|
#include <sys/mman.h>
|
|
|
|
namespace HPHP { namespace Transl {
|
|
TRACE_SET_MOD(txlease);
|
|
|
|
bool
|
|
Lease::amOwner() const {
|
|
return m_held && m_owner == pthread_self();
|
|
}
|
|
|
|
/*
|
|
* Multi-threaded scenarios for lease interleaving are hard to tease out.
|
|
* The "gremlin" is a pseudo-thread that sometimes steals our lease while
|
|
* we're running in the TC.
|
|
*
|
|
* The gremlin's pthread id is the bitwise negation of our own. Yes,
|
|
* hypothetical wacky pthread implementations can break this. It's
|
|
* DEBUG-only, folks.
|
|
*/
|
|
static inline pthread_t gremlinize_threadid(pthread_t tid) {
|
|
return (pthread_t)(~((int64_t)tid));
|
|
}
|
|
|
|
void Lease::gremlinLock() {
|
|
if (amOwner()) {
|
|
TRACE(2, "Lease: gremlinLock dropping lease\n");
|
|
drop();
|
|
}
|
|
pthread_mutex_lock(&m_lock);
|
|
TRACE(2, "Lease: gremlin grabbed lock\n ");
|
|
m_held = true;
|
|
m_owner = gremlinize_threadid(pthread_self());
|
|
}
|
|
|
|
void
|
|
Lease::gremlinUnlockImpl() {
|
|
if (m_held && m_owner == gremlinize_threadid(pthread_self())) {
|
|
TRACE(2, "Lease: gremlin dropping lock\n ");
|
|
pthread_mutex_unlock(&m_lock);
|
|
m_held = false;
|
|
}
|
|
}
|
|
|
|
// acquire: also returns true if we are already the writer.
|
|
bool Lease::acquire(bool blocking /* = false */ ) {
|
|
if (amOwner()) {
|
|
return true;
|
|
}
|
|
int64_t expire = m_hintExpire;
|
|
int64_t expireDiff = expire - Timer::GetCurrentTimeMicros();
|
|
if (!blocking && (m_held ||
|
|
(expireDiff > 0 && m_owner != pthread_self()))) {
|
|
return false;
|
|
}
|
|
checkRank(RankWriteLease);
|
|
if (0 == (blocking ?
|
|
pthread_mutex_lock(&m_lock) :
|
|
pthread_mutex_trylock(&m_lock))) {
|
|
TRACE(4, "thr%" PRIx64 ": acquired lease, called by %p,%p\n",
|
|
pthread_self(), __builtin_return_address(0),
|
|
__builtin_return_address(1));
|
|
if (debug) {
|
|
pushRank(RankWriteLease);
|
|
if (expire != 0 && m_owner != pthread_self()) {
|
|
m_hintGrabbed++;
|
|
TRACE(3,
|
|
"thr%" PRIx64 ": acquired hinted lease"
|
|
", expired %" PRId64 "us ago\n",
|
|
pthread_self(), -expireDiff);
|
|
} else if (expire != 0 && m_owner == pthread_self()) {
|
|
m_hintKept++;
|
|
}
|
|
Translator::Get()->unprotectCode();
|
|
}
|
|
|
|
m_owner = pthread_self();
|
|
m_hintExpire = 0;
|
|
m_held = true;
|
|
return true;
|
|
}
|
|
if (blocking) {
|
|
TRACE(3, "thr%" PRIx64 ": failed to acquired lease in blocking mode\n",
|
|
pthread_self());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Lease::drop(int64_t hintExpireDelay) {
|
|
assert(amOwner());
|
|
TRACE(4, "thr%" PRIx64 ": dropping lease, called by %p,%p\n",
|
|
pthread_self(), __builtin_return_address(0),
|
|
__builtin_return_address(1));
|
|
if (debug) {
|
|
popRank(RankWriteLease);
|
|
Translator::Get()->protectCode();
|
|
}
|
|
m_hintExpire = hintExpireDelay > 0 ?
|
|
Timer::GetCurrentTimeMicros() + hintExpireDelay : 0;
|
|
m_held = false;
|
|
pthread_mutex_unlock(&m_lock);
|
|
}
|
|
|
|
LeaseHolderBase::LeaseHolderBase(Lease& l, LeaseAcquire acquire,
|
|
bool blocking)
|
|
: m_lease(l), m_haveLock(false), m_acquired(false) {
|
|
assert(IMPLIES(blocking, acquire == LeaseAcquire::ACQUIRE));
|
|
if (!m_lease.amOwner() && acquire == LeaseAcquire::ACQUIRE) {
|
|
m_acquired = m_lease.acquire(blocking);
|
|
}
|
|
m_haveLock = m_lease.amOwner();
|
|
}
|
|
|
|
LeaseHolderBase::~LeaseHolderBase() {
|
|
if (m_acquired && m_lease.amOwner()) {
|
|
m_lease.drop(Lease::kStandardHintExpireInterval);
|
|
}
|
|
}
|
|
|
|
bool LeaseHolderBase::acquire() {
|
|
assert(!m_acquired);
|
|
assert(m_haveLock == m_lease.amOwner());
|
|
if (m_haveLock) {
|
|
return true;
|
|
}
|
|
return m_haveLock = m_acquired = m_lease.acquire();
|
|
}
|
|
|
|
}}
|