Repository navigation
runtime interp monitor
ceragon edited this page Jun 12, 2022
·
5 revisions
class BasicObjectLock {
BasicLock _lock;
// 锁对象的地址
oop _obj;
static int obj_offset_in_bytes() {
return offset_of(BasicObjectLock, _obj);
}
};class BasicLock {
volatile markOop _displaced_header;
void set_displaced_header(markOop header) { _displaced_header = header; }
};初始情况
| 索引 | 名称 | 介绍 |
|---|---|---|
| 0 | save rbp | |
| -9 | initial_sp | |
| -9 | monitor_block_top |
有一个值之后
| 索引 | 名称 | 介绍 |
|---|---|---|
| 0 | save rbp | |
| -9 | initial_sp | |
| -10 | monitor_block_top |
有两个不同值之后
| 索引 | 名称 | 介绍 |
|---|---|---|
| 0 | save rbp | |
| -9 | initial_sp | |
| -11 | monitor_block_top |
REGISTER_DECLARATION(Register, c_rarg1, rsi);
void TemplateTable::monitorenter() {
// 调用 monitorEnter 之前需要保证 synchronize 的对象在操作数栈的栈顶,也就是 rax 寄存器
// 监视的对象不能为空,否则会空指针异常
__ null_check(rax);
// rsi 寄存器
Register rmon = c_rarg1;
// 异或 相同为0,则 rmon 最终为0
__ xorl(rmon, rmon); // points to free slot or NULL
{
// 初始情况下,rtop,rbot 是一个值
Label entry, loop, exit;
// rbp 栈帧基址,monitor_block_top 存储在了栈上的偏移 9 的位置
const Address monitor_block_top(rbp,
frame::interpreter_frame_monitor_block_top_offset * wordSize);
// rcx
Register rtop = c_rarg3;
// 将 monitor_block_top 置入 rcx 中
__ movptr(rtop, monitor_block_top);
// 这里存储的是栈帧顶部的地址
const Address monitor_block_bot(rbp,
frame::interpreter_frame_initial_sp_offset * wordSize);
// rdx
Register rbot = c_rarg2;
// rbot: monitor_block 的底部
__ lea(rbot, monitor_block_bot);
// 跳转到 entry 标签
__ jmpb(entry);
// loop 开始 ======================
// loop 标签处
__ bind(loop);
// monitor_block_top 存储的是 BasicObjectLock 结构体
// 查看一下结构体中锁对象的位置是否没被占用
__ cmpptr(Address(rtop, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD);
// 比较并移动,如果锁对象的位置没有被占用
// 将 monitor_block_top 值放入 rmon: rsi 寄存器
__ cmovptr(Assembler::equal, rmon, rtop);
// 比较一下 rax 中存储的锁对象地址,和 monitor_block_top 或者说栈上存储的地址是否一样
__ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));
// 一样的话跳转到 exit 标签
__ jccb(Assembler::equal, exit);
const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
// 否则 monitor_block_top 地址向上扩展一个 BasicObjectLock 结构体的大小
// 因为 monitor_block 在栈上是从低向高使用,而不是从高向低
__ addptr(rtop, entry_size);
// loop 结束 =============================
__ bind(entry);
// rbot: monitorBlock 的底部, rtop: monitorBlock的顶部
// 由于是从低到高遍历,所以遍历到头就可以停止了
__ cmpptr(rtop, rbot);
// 没到头就继续循环
__ jcc(Assembler::notEqual, loop);
__ bind(exit);
}
// 上面的步骤是从 monitor_block 表中找一个空位,
// 首个对象会直接遇到 rtop == rbot 的情况
// 判断 rmon 是否为0
__ testptr(rmon, rmon);
// 不为 0 就表示找到了空位
__ jcc(Assembler::notZero, allocated);
{
// =============== allocate 空间扩展 ================
Label entry, loop;
// 1. compute new pointers // rsp: old expression stack top
// monitor_block_bot, BasicObjectLock 表的底部
__ movptr(rmon, monitor_block_bot); // rmon: old expression stack bottom
// 把 rsp 向下扩展一个 BasicObjectLock 对象的空间
__ subptr(rsp, entry_size); // move expression stack top
// 第一次产生锁的时候,rmon 和 rsp 的值是一致的,BasicObjectLock 表的底部也下移一个对象位置
__ subptr(rmon, entry_size); // move expression stack bottom
// 将栈顶作为 monitor_block 的顶部
__ mov(rtop, rsp); // set start value for copy loop
// 产生了新的底部
__ movptr(monitor_block_bot, rmon); // set new monitor block bottom
// 可以看到,上面部分只负责扩充空间
__ jmp(entry);
// =================================================
// 2. move expression stack contents
__ bind(loop);
__ movptr(rbot, Address(rtop, entry_size)); // load expression stack
// word from old location
__ movptr(Address(rtop, 0), rbot); // and store it at new location
__ addptr(rtop, wordSize); // advance to next word
__ bind(entry);
// 如果是第一次出现锁,则 rtop 和 rmon 一定相同
__ cmpptr(rtop, rmon); // check if bottom reached
// 不同会循环
__ jcc(Assembler::notEqual, loop); // if not at bottom then
}
__ bind(allocated);
// 让 rbcp 指向下一个字节码
__ increment(rbcp);
// 保存对象到空的位置
__ movptr(Address(rmon, BasicObjectLock::obj_offset_in_bytes()), rax);
__ lock_object(rmon);
// __ save_bcp();
movptr(Address(rbp, frame::interpreter_frame_bcp_offset * wordSize), _bcp_register);
// 检查 stackOverFlow
__ generate_stack_overflow_check(0);
// 跳转到下一个字节码
__ dispatch_next(vtos);
}void InterpreterMacroAssembler::lock_object(Register lock_reg) {
// lock_reg: rsi 寄存器,且记录的是 BasicObjectLock
// 默认不启用,否则会直接使用重量级锁
if (UseHeavyMonitors) {
call_VM(noreg,
CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
lock_reg);
} else {
// ================= cmpxchg 进行加锁 ============
// rcx
const Register obj_reg = c_rarg3;
// 让 rcx 记录锁对象的地址
movptr(obj_reg, Address(lock_reg, obj_offset));
if (UseBiasedLocking) {
// 如果启用了偏向锁,则会进入偏向锁流程
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp_reg, false, done, &slow_case);
}
const Register swap_reg = rax; // Must use rax for cmpxchg instruction
// 立即数 1 放到 rax 寄存器上
movl(swap_reg, (int32_t)1);
// 每个对象的头 8字节 mark word
// Load (object->mark() | 1) into swap_reg %rax
// 说白了将 markWord 的最低位设为1
// 之所要要将最低位设为1,因为期望的是原本无锁,经过操作之后变为了有锁
// 无锁状态是 01,若已经加锁,则状态是 00,或者重量级锁 10
// 因此如果原本就是有锁,那么 cmpxchg 必然失败
// 只有原本是无锁,且 cmpxchg 操作成功,才说明加锁成功
orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
// _lock 字段的偏移,默认是0
const int lock_offset = BasicObjectLock::lock_offset_in_bytes ();
// _displaced_header 字段的偏移,默认是0
const int mark_offset = lock_offset +
BasicLock::displaced_header_offset_in_bytes();
// 直接先将 markWord 保存到栈上(之前选择好的一个 BasicObjectLock 格子上)
movptr(Address(lock_reg, mark_offset), swap_reg);
// 如果是多处理器架构,则增加一个 lock 前缀,
// 用于保证下一个指令原子化执行
if (os::is_MP()) lock();
// 虽然 cmpxchg 是一条指令,但是隐含了两个操作
// 先从 3缓 读取数据所在的缓存行到 1缓 中
// 比较读取的数据与 rax 寄存器的值
// 如果相等,则修改目的地址的值为 lock_reg 的值
// 以上涉及了对于三缓的两次操作,读和写。
// 如果不加 lock 前缀,会造成刚读取完值,就被其他核心修改的结果。
// 此外 lock_reg 是栈上 basicObjectLock 的首地址
// 下面这个命令的目的就是把锁对象的 mark_word 修改成 basicObjectLock 的首地址
cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
// 如果上个步骤修改成功了,则标志寄存器会出现0,
// 然后就可以跳转到 done 处了
// 然而这只能保证说设置锁标记成功了,并不代表自己拿到锁了!!!
jcc(Assembler::zero, done);
// =======================================
// ==================== 比较并替换失败 ================
// swap_reg: 由于 cmpxchg 失败,那么 rax 的值会变成最新的 markWord
// rsp: 栈指针
// 将 markWord 与 rsp 相减,乍看会觉得莫名其妙,实则是在判断锁重入!!!
// 因为 cmpxchg 失败,说明其他线程占有了锁,
// 如果是占有了锁,那么 markWord 的值会变成占有者线程栈上的 basicObjectLock 的首地址
// 通过比较当前线程 rsp 指针的值,和 basicObjectLock 的首地址,即可判断是否本线程占有了锁
subptr(swap_reg, rsp);
const int zero_bits = 7;
// 补码的值为: 11111111111111111111000000000111
// 差值与上页的大小,0 的位直接置为0
andptr(swap_reg, zero_bits - os::vm_page_size());
// 将结果保存在栈上
movptr(Address(lock_reg, mark_offset), swap_reg);
// 如果 swap_reg 的值是0,就跳转到 done
// 在轻量级锁生效时,尾数的3位是 000
// 因为如果要满足为0,一是 swap_reg 和 rsp 的差值在一个页大小的范围内
// 其次锁标记的状态还必须是轻量级锁,也就是 000
// 另外这里只是快速判断,如果判断成功,则判断锁重入的效率会很高,
// 判断失败,则被迫调用 vm 的 monitorEnter
jcc(Assembler::zero, done);
// 只有偏向锁用到了这个 label
bind(slow_case);
// 调用 vm 的 monitorEnter
call_VM(noreg,
CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
lock_reg);
bind(done);
}
}void MacroAssembler::call_VM(Register oop_result,
address entry_point,
Register arg_1,
bool check_exceptions) {
// oop_result: null
// entry_point: monitorenter 的vm调用方法
// arg_1: basicObjectLock 对象的地址, Register rmon = c_rarg1; 且是 c_rarg1 寄存器
// check_exceptions: false
Label C, E;
// 将当前 jmp(E) 的地址压栈
// 跳转到 C 执行
call(C, relocInfo::none);
jmp(E);
bind(C);
pass_arg1(this, arg_1);
// 执行调用
call_VM_helper(oop_result, entry_point, 1, check_exceptions);
ret(0);
bind(E);
}
static void pass_arg1(MacroAssembler* masm, Register arg) {
// 根据上下文,arg 是 c_rarg1 寄存器
if (c_rarg1 != arg ) {
masm->mov(c_rarg1, arg);
}
}void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
// 由于已经将 call_VM 调用之后的返回地址压栈了
// 所以真实的 rsp 地址应该 + 1
lea(rax, Address(rsp, wordSize));
call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions);
}
void MacroAssembler::call_VM_base(Register oop_result,
Register java_thread,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
// oop_result: null
// java_thread: noreg
// last_java_sp: rax (调用 vm 之前的栈地址)
// entry_point: monitorenter 的 vm 调用
// number_of_arguments: 1
// check_exceptions: false
if (!java_thread->is_valid()) {
java_thread = r15_thread;
}
// c_rarg0: rdi
mov(c_rarg0, r15_thread);
// 修改 java 线程对象的 last_java_sp 和 last_java_fp 两个字段
set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);
// 调用 vm 的方法
MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
// reset last Java frame
// Only interpreter should have to clear fp
reset_last_Java_frame(java_thread, true);
}
void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp) {
// we must set sp to zero to clear frame
movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
if (clear_fp) {
movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
}
movptr(Address(java_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
}void MacroAssembler::call_VM_leaf_base(address entry_point, int num_args) {
Label L, E;
// 按理说 rsp 的值是个地址,为啥能和 15 比较大小
testl(rsp, 15);
jcc(Assembler::zero, L);
// 正常流程的话,开辟一个 8 字节的栈空间,用于存储返回地址
subq(rsp, 8);
{
// 调用方法
call(RuntimeAddress(entry_point));
}
// 调用结束恢复栈帧
addq(rsp, 8);
jmp(E);
bind(L);
{
call(RuntimeAddress(entry_point));
}
bind(E);
}void TemplateTable::monitorexit() {
__ null_check(rax);
{
Label entry, loop;
Register rtop = c_rarg1;
const Address monitor_block_top(
rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
__ movptr(rtop, monitor_block_top);
const Address monitor_block_bot(
rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
__ lea(rbot, monitor_block_bot);
__ jmpb(entry);
__ bind(loop);
__ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));
__ jcc(Assembler::equal, found);
__ addptr(rtop, entry_size);
__ bind(entry);
__ cmpptr(rtop, rbot);
__ jcc(Assembler::notEqual, loop);
}
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_illegal_monitor_state_exception));
__ should_not_reach_here();
__ bind(found);
__ push_ptr(rax);
__ unlock_object(rtop);
__ pop_ptr(rax);
}void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
if (UseHeavyMonitors) {
call_VM(noreg,
CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),
lock_reg);
} else {
Label done;
save_bcp();
lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes()));
movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()));
movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD);
if (UseBiasedLocking) {
biased_locking_exit(obj_reg, header_reg, done);
}
movptr(header_reg, Address(swap_reg,
BasicLock::displaced_header_offset_in_bytes()));
testptr(header_reg, header_reg);
jcc(Assembler::zero, done);
if (os::is_MP()) lock();
cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
jcc(Assembler::zero, done);
movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), obj_reg);
call_VM(noreg,
CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),
lock_reg);
bind(done);
restore_bcp();
}
}typedef class oopDesc* oop;
class Handle {
oop* _handle;
oop obj() const {
return _handle == NULL ? (oop)NULL : *_handle;
}
oop non_null_obj() const {
return *_handle;
}
oop operator () () const {
return obj();
}
oop operator -> () const {
// 被重载之后,实际返回的是 oopDesc 结构体
// 相当于类型转化
return non_null_obj();
}
};
markOop oopDesc::mark() const {
// as_oop() 返回对象的首地址
// mark_offset_in_bytes() markWord 的偏移量
// 总之就是获取 markWord 的包装类 markOop
return HeapAccess<MO_VOLATILE>::load_at(as_oop(), mark_offset_in_bytes());
}
inline oop as_oop() const {
return const_cast<oopDesc*>(this);
}class markOopDesc: public oopDesc {
uintptr_t value() const { return (uintptr_t) this; }
enum { age_bits = 4,
lock_bits = 2,
biased_lock_bits = 1,
max_hash_bits = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits,
cms_bits = LP64_ONLY(1) NOT_LP64(0),
epoch_bits = 2
};
enum { lock_shift = 0,
biased_lock_shift = lock_bits,
age_shift = lock_bits + biased_lock_bits,
cms_shift = age_shift + age_bits,
hash_shift = cms_shift + cms_bits,
epoch_shift = hash_shift
};
enum {
// lock_bits: 2
// lock_mask: 0b11
lock_mask = right_n_bits(lock_bits),
// lock_mask_in_place: 0b11
lock_mask_in_place = lock_mask << lock_shift,
// lock_bits: 2
// biased_lock_bits: 1
// biased_lock_mask = 0b111
biased_lock_mask = right_n_bits(lock_bits + biased_lock_bits),
biased_lock_mask_in_place= biased_lock_mask << lock_shift,
biased_lock_bit_in_place = 1 << biased_lock_shift,
age_mask = right_n_bits(age_bits),
age_mask_in_place = age_mask << age_shift,
epoch_mask = right_n_bits(epoch_bits),
epoch_mask_in_place = epoch_mask << epoch_shift,
cms_mask = right_n_bits(cms_bits),
cms_mask_in_place = cms_mask << cms_shift
};
enum { locked_value = 0,
unlocked_value = 1,
monitor_value = 2,
marked_value = 3,
biased_lock_pattern = 5
};
inline intptr_t mask_bits (intptr_t x, intptr_t m) {
return x & m;
}
bool is_neutral() const {
// biased_lock_mask_in_place: 0b111
// 判断 markWord 后三位的值是否等于 1
// 也就是说只要末尾为1,就是中性状态,也就是无锁
return (mask_bits(value(), biased_lock_mask_in_place) == unlocked_value);
}
bool has_locker() const {
// lock_mask_in_place: 0b11
// 判断 markWord 后两位是否等于0
// 如果相等,则表示轻量级锁加锁成功
return ((value() & lock_mask_in_place) == locked_value);
}
bool has_monitor() const {
// monitor_value: 0b0010
// 只要倒数第二位为1,就有 monitor,也就是重量级锁状态
return ((value() & monitor_value) != 0);
}
ObjectMonitor* monitor() const {
// monitor_value: 0b0010
// 0 异或任何数都等于它本身
return (ObjectMonitor*) (value() ^ monitor_value);
}
BasicLock* locker() const {
return (BasicLock*) value();
}
};void InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem) {
// 在栈上分配一个 Handle 对象,持有锁对象的首地址
Handle h_obj(thread, elem->obj());
if (UseBiasedLocking) {
ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
} else {
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
}
}void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
markOop mark = obj->mark();
// 判断 markWord 尾数是否为 1
if (mark->is_neutral()) {
// 在栈帧上有个 BasicObjectLock,第一个字段就是 BasicLock
// 相当于在栈上保存旧的 markWord值
lock->set_displaced_header(mark);
// 这里的意思是,尝试将对象头的 markWord 改成 BasicLock 对象的首地址
if (mark == obj()->cas_set_mark((markOop) lock, mark)) {
// 如果旧值与mark值相等,则修改成功,同时自己持有了锁
return;
}
} else if (mark->has_locker() &&
THREAD->is_lock_owned((address)mark->locker())) {
// 先判断了是否是轻量级锁
// 由于轻量级锁状态下,markWord 记录的是持有锁线程栈帧中的 BasicLock 地址
// 所以判断一下该地址是否在当前线程的栈帧范围内
// 如果都满足,则锁重入成功
// 为了保证 markWord 存储的一致性,保存在第一个持有锁的栈帧中即可
// 当前栈帧已经设置过的 displaced_header 字段就可以置空了
lock->set_displaced_header(NULL);
return;
}
// 当前是轻量级锁状态,且占有者不是当前线程,那么执行锁膨胀
// 将当前栈帧上的 displaced_header 置为空,因为没有必要了
// 重量级锁之后,markWord 会缓存到 monitor 中
lock->set_displaced_header(markOopDesc::unused_mark());
ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_monitor_enter)->enter(THREAD);
}
markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) {
// as_oop() + mark_offset_in_bytes() 组成了一个地址,也就是对象的头部
// 如果该位置的值 == old_mark,则修改为 new_mark
return HeapAccess<>::atomic_cmpxchg_at(new_mark, as_oop(), mark_offset_in_bytes(), old_mark);
}ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self,
oop object,
const InflateCause cause) {
// 本方法的目的是生成或者返回一个 Monitor 对象
for (;;) {
const markOop mark = object->mark();
// 已经是重量级锁
if (mark->has_monitor()) {
// 重量级锁的话,markWord 记录的是 monitor 对象的地址
ObjectMonitor * inf = mark->monitor();
return inf;
}
// 如果重量级锁膨胀中,那么会直接把 markWord 置为0
if (mark == markOopDesc::INFLATING()) {
// TODO
ReadStableMark(object);
continue;
}
// markWord 末尾是0
if (mark->has_locker()) {
// 从线程的 ObjectMonitor 池中获取一个对象
ObjectMonitor * m = omAlloc(Self);
// 重置成员变量
m->Recycle();
m->_Responsible = NULL;
m->_recursions = 0;
// 重置自旋次数
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;
// 修改 markword 为膨胀中
markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
if (cmp != mark) {
// 修改失败,释放 m 对象到池中
omRelease(Self, m, true);
continue;
}
// 修改成功
// 取出 markWord,注意这个 markWord 实际上是 BasicObjectLock -> BasicLock 的地址
markOop dmw = mark->displaced_mark_helper();
// 保存 BasicLock 的地址
m->set_header(dmw);
// locker() 其实就是 BasicLock 的地址
m->set_owner(mark->locker());
// 将对象保存到 monitor 中
m->set_object(object);
// 由于变成了重量级锁,因此 markWord 的值需要变成 monitor 对象的地址
// 但是不管怎样,m 的地址的末尾必须是 0
object->release_set_mark(markOopDesc::encode(m));
// 膨胀次数 +1
OM_PERFDATA_OP(Inflations, inc());
return m;
}
// 这种情况会出现,是因为已经膨胀成了重量级锁
// 因此即使锁释放了,下次再获得锁,也会以重量级锁的方式来处理
// 分配 monitor 和重置变量就不再介绍了
ObjectMonitor * m = omAlloc(Self);
m->Recycle();
m->set_header(mark);
m->set_owner(NULL);
m->set_object(object);
m->_recursions = 0;
m->_Responsible = NULL;
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;
// 比较并替换 markWord 的值
if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) {
// 修改失败则他人拿到了锁,需要释放 monitor 对象并重试
m->set_object(NULL);
m->set_owner(NULL);
m->Recycle();
omRelease(Self, m, true);
m = NULL;
continue;
}
// 锁膨胀次数 +1
OM_PERFDATA_OP(Inflations, inc());
return m;
}
}
static markOop INFLATING() { return (markOop) 0; } // inflate-in-progressclass ObjectMonitor {
void * volatile _owner;
// 等待队列
ObjectWaiter * volatile _cxq;
// 等待队列中,优先获取到锁的线程
Thread * volatile _Responsible;
// TODO: 应该是被唤醒的线程
Thread * volatile _succ;
};class Thread: public ThreadShadow {
// ObjectMonitor 对象池
ObjectMonitor* omFreeList;
volatile intptr_t _Stalled;
ParkEvent * _ParkEvent;
};ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL; // 全局对象池
ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
for (;;) {
ObjectMonitor * m;
m = Self->omFreeList;
if (m != NULL) {
// 有可用对象
// 已经抢占了 list 的第一个元素,所以要移出队列
Self->omFreeList = m->FreeNext;
// 对象池数量 -1
Self->omFreeCount--;
// 默认为true,用于支持锁降级
if (MonitorInUseLists) {
// 这样占有的锁对象还能关联到对象池
m->FreeNext = Self->omInUseList;
// 将 m 放入使用列表中
Self->omInUseList = m;
// 使用中的数量 +1
Self->omInUseCount++;
} else {
m->FreeNext = NULL;
}
return m;
}
// 线程本地的对象池不够用了,看看全局对象池
// 这里并不是直接从全局的池子里取对象
// 而是取出多个对象,然后填充到线程的 omFreeList 中
if (gFreeList != NULL) {
// 后面就不看了
}
}
}void ObjectMonitor::enter(TRAPS) {
Thread * const Self = THREAD;
// 比较并修改 monitor 的 owner 字段
void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
if (cur == NULL) {
// cur 是返回的旧值,旧值为空,说明加锁成功
return;
}
// cur 不为空,那么一定指向某个线程的首地址
if (cur == Self) {
// 持有锁的线程就是本线程,那么锁重入成功
_recursions++;
return;
}
// 判断 cur 是否在线程的栈空间内
// TODO: 不太懂为啥有这个判断
if (Self->is_lock_owned ((address)cur)) {
_recursions = 1;
_owner = Self;
return;
}
// 当前线程缓存 monitor 对象
Self->_Stalled = intptr_t(this);
// Knob_SpinEarly 默认是 1
// TrySpin() 尝试自旋加锁
if (Knob_SpinEarly && TrySpin (Self) > 0) {
// 加锁成功了,将取消缓存 monitor 对象
Self->_Stalled = 0;
return;
}
JavaThread * jt = (JavaThread *) Self;
Atomic::inc(&_count);
{
Self->set_current_pending_monitor(this);
for (;;) {
// 正常情况下,EnterI 都会拿到锁再出来
EnterI(THREAD);
if (!ExitSuspendEquivalent(jt)) break;
_recursions = 0;
exit(false, Self);
}
Self->set_current_pending_monitor(NULL);
}
Atomic::dec(&_count);
Self->_Stalled = 0;
OM_PERFDATA_OP(ContendedLockAttempts, inc());
}void ObjectMonitor::EnterI(TRAPS) {
Thread * const Self = THREAD;
// 先尝试加锁
if (TryLock (Self) > 0) {
return;
}
// 自旋加锁
if (TrySpin (Self) > 0) {
return;
}
// 被迫进入等待队列
// 新建一个 Waiter
ObjectWaiter node(Self);
// Thread 的一个成员
Self->_ParkEvent->reset();
// 重置 waiter
node._prev = (ObjectWaiter *) 0xBAD;
node.TState = ObjectWaiter::TS_CXQ;
ObjectWaiter * nxt;
for (;;) {
node._next = nxt = _cxq;
// 尝试将自己放到 _cxq 的位置
// 成功了就退出循环
if (Atomic::cmpxchg(&node, &_cxq, nxt) == nxt) break;
// 有竞争者,失败了再尝试加锁一次
if (TryLock (Self) > 0) {
return;
}
}
// nxt 会得到 _cxq 的旧值
if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
// 第一次进等待队列,就会出现这个情况
// 把自己放到 _Responsible 中
Atomic::replace_if_null(Self, &_Responsible);
}
int nWakeups = 0;
int recheckInterval = 1;
for (;;) {
// 又一次尝试加锁
if (TryLock(Self) > 0) break;
if ((SyncFlags & 2) && _Responsible == NULL) {
// 首先说明在上一步中,没有成功把自己设置成 _Responsible
Atomic::replace_if_null(Self, &_Responsible);
}
if (_Responsible == Self || (SyncFlags & 1)) {
// 只要等待着是自己,那么阻塞吧
// 超时时间默认1ms
Self->_ParkEvent->park((jlong) recheckInterval);
// 需要注意,下一行代码会执行,有两个条件
// 1: 超时时间到了
// 2: 被唤醒了
// 无论什么情况,等待时间加倍
recheckInterval *= 8;
// MAX_RECHECK_INTERVAL: 1000
if (recheckInterval > MAX_RECHECK_INTERVAL) {
recheckInterval = MAX_RECHECK_INTERVAL;
}
} else {
// 阻塞,直到被唤醒
Self->_ParkEvent->park();
}
// 被唤醒了,加锁试下
if (TryLock(Self) > 0) break;
// 没加锁成功,唤醒次数 +1
++nWakeups;
// Knob_SpinAfterFutile: 默认值是1
// 因此会在进行一次自旋
if ((Knob_SpinAfterFutile & 1) && TrySpin(Self) > 0) break;
// Knob_ResetEvent: 默认值是 0
if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
Self->_ParkEvent->reset();
OrderAccess::fence();
}
if (_succ == Self) _succ = NULL;
// 编译器,指令双屏障
OrderAccess::fence();
}
// 由于上面死循环的退出条件只有一个,就是获取到锁
// 下面的代码就是让自己退出等待队列
UnlinkAfterAcquire(Self, &node);
// 如果被唤醒者是自己,置空
if (_succ == Self) _succ = NULL;
if (_Responsible == Self) {
// 如果自己是优先获取锁的,置空
_Responsible = NULL;
// 屏障
OrderAccess::fence();
}
if (SyncFlags & 8) {
OrderAccess::fence();
}
}int ObjectMonitor::TryLock(Thread * Self) {
void * own = _owner;
if (own != NULL) return 0;
// 比较为空,并进行替换为 Self
if (Atomic::replace_if_null(Self, &_owner)) {
// 成功
return 1;
}
// 失败
return -1;
}static int Knob_PreSpin = 10;
int ObjectMonitor::TrySpin(Thread * Self) {
// 固定次数自旋已经被废弃了
int ctr = Knob_FixedSpin;
if (ctr != 0) {
while (--ctr >= 0) {
if (TryLock(Self) > 0) return 1;
SpinPause();
}
return 0;
}
// 循环11 次
for (ctr = Knob_PreSpin + 1; --ctr >= 0;) {
if (TryLock(Self) > 0) {
// 加锁成功
// x 的值是0
int x = _SpinDuration;
// Knob_SpinLimit: 值是0
if (x < Knob_SpinLimit) {
if (x < Knob_Poverty) x = Knob_Poverty;
_SpinDuration = x + Knob_BonusB;
}
// 上面没太看懂,只会走到这里
return 1;
}
SpinPause();
}
// ctr = 0
ctr = _SpinDuration;
// Knob_SpinBase 默认值也是0
if (ctr < Knob_SpinBase) ctr = Knob_SpinBase;
if (ctr <= 0) return 0;
// 下面的代码更是看不懂在干嘛
}