📄 aemonsem.java
字号:
String class_name = elt.getClassName();
int line_number = elt.getLineNumber();
monSemData new_entry = new monSemData( class_name, line_number);
if ( is_monitor ){
debug_monitors.put( this, new_entry );
}else{
debug_semaphores.put( this, new_entry );
}
if ( DEBUG_CHECK_DUPLICATES ){
monSemData existing_name_entry = (monSemData)debug_name_mapping.get( name );
if ( existing_name_entry == null ){
debug_name_mapping.put( name, new_entry );
}else{
if ( ( !existing_name_entry.class_name.equals( class_name )) ||
existing_name_entry.line_number != line_number ){
Debug.out( new Exception("Duplicate AEMonSem name '" + name + "'"));
}
}
}
}
}
}
protected void
debugEntry()
{
//if ( trace ){
// System.out.println( Debug.getStackTrace( true, false ));
//}
try{
// bad things are:
// A->B and somewhere else B->A
// or
// A(inst1) -> A(inst2)
Stack stack = (Stack)tls.get();
if ( stack.size() > 64 ){
StringBuffer sb = new StringBuffer(1024);
for (int i=0;i<stack.size();i++){
AEMonSem mon = (AEMonSem)stack.get(i);
sb.append( "$" + mon.name );
}
Debug.out( "**** Whoaaaaaa, AEMonSem debug stack is getting too large!!!! **** " + sb );
}
if ( !stack.isEmpty()){
String recursion_trace = "";
/* not very useful
if ( (!is_monitor) &&
((AEMonSem)stack.peek()).is_monitor ){
if ( !debug_sem_in_mon.contains( name )){
recursion_trace += ( recursion_trace.length()==0?"":"\r\n" ) +
"Semaphore reservation while holding a monitor: sem = " + name+ ", mon = " + ((AEMonSem)stack.peek()).name;
debug_sem_in_mon.add( name );
}
}
*/
StringBuffer sb = new StringBuffer();
// not very interesting for semaphores as these tend to get left on stack traces when
// asymetric usage (which is often)
boolean check_recursion = is_monitor && !debug_recursions.contains( name );
String prev_name = null;
for (int i=0;i<stack.size();i++){
AEMonSem mon = (AEMonSem)stack.get(i);
if ( check_recursion ){
if ( mon.name.equals( name ) &&
mon != this ){
recursion_trace +=
( recursion_trace.length()==0?"":"\r\n" ) +
"Recursive locks on different instances: " + name;
debug_recursions.add( name );
}
}
// remove consecutive duplicates
if ( prev_name == null || !mon.name.equals( prev_name )){
sb.append("$");
sb.append(mon.name);
}
prev_name = mon.name;
}
sb.append( "$" );
sb.append( name );
sb.append( "$" );
String trace_key = sb.toString();
if ( recursion_trace.length() > 0 ){
Debug.outNoStack( recursion_trace + "\r\n " + trace_key );
}
last_trace_key = trace_key;
if ( !is_monitor ){
// only add semaphores to the stack if they aren't already present.
// This is because we can reserve a semaphore on one thread and
// release it on another. This will grow the stack indefinitely
boolean match = false;
for (int i=0;i<stack.size();i++){
AEMonSem ms = (AEMonSem)stack.get(i);
if ( ms.name.equals( name )){
match = true;
break;
}
}
if ( !match ){
stack.push( this );
}
}else{
stack.push( this );
}
synchronized( debug_traces ){
if ( debug_traces.get(trace_key) == null ){
Thread thread = Thread.currentThread();
String thread_name = thread.getName() + "[" + thread.hashCode() + "]";
String stack_trace = Debug.getStackTrace(true, false);
Iterator it = debug_traces.keySet().iterator();
while( it.hasNext()){
String old_key = (String)it.next();
String[] data = (String[])debug_traces.get(old_key);
String old_thread_name = data[0];
String old_trace = data[1];
// if identical thread then we can ignore this as
// it can't happen concurrently
if ( thread_name.equals( old_thread_name )){
continue;
}
// find the earliest occurrence of a common monitor - no point in searching
// beyond it
// e.g. a -> b -> c -> g
// x -> y -> b -> z
// stop at b because beyond this things are "protected"
int earliest_common = stack.size();
int common_count = 0;
for (int i=0;i<stack.size();i++){
String n1 = ((AEMonSem)stack.get(i)).name;
int p1 = old_key.indexOf( "$" + n1 + "$");
if ( p1 != -1 ){
common_count++;
earliest_common = Math.min( earliest_common, i+1 );
}
}
// need at least 2 common monitors for chance of deadlock
if ( common_count >= 2 ){
for (int i=0;i<earliest_common;i++){
AEMonSem ms1 = (AEMonSem)stack.get(i);
if ( !ms1.is_monitor ){
continue;
}
String n1 = ms1.name;
for (int j=i+1;j<stack.size();j++){
AEMonSem ms2 = (AEMonSem)stack.get(j);
if ( !ms2.is_monitor ){
continue;
}
String n2 = ms2.name;
// same object recursion already tested above
if ( !n1.equals( n2 )){
int p1 = old_key.indexOf( "$" + n1 + "$");
int p2 = old_key.indexOf( "$" + n2 + "$");
if ( p1 != -1 && p2 != -1 && p1 > p2 ){
String reciprocal_log = trace_key + " / " + old_key;
if ( !debug_reciprocals.contains( reciprocal_log )){
debug_reciprocals.add( reciprocal_log );
Debug.outNoStack(
"AEMonSem: Reciprocal usage:\r\n" +
" " + trace_key + "\r\n" +
" [" + thread_name + "] " + stack_trace + "\r\n" +
" " + old_key + "\r\n" +
" [" + old_thread_name + "] " + old_trace );
}
}
}
}
}
}
}
debug_traces.put( trace_key, new String[]{ thread_name, stack_trace });
// look through all the traces for an A->B and B->A
}
}
}else{
last_trace_key = "$" + name + "$";
stack.push( this );
}
}catch( Throwable e ){
try{
Debug.printStackTrace(e);
}catch( Throwable f ){
}
}
}
protected void
debugExit()
{
try{
Stack stack = (Stack)tls.get();
if ( is_monitor ){
// skip over any sem reserves within a sync block
while( stack.peek() != this ){
stack.pop();
}
stack.pop();
}else{
// for semaphores we can release stuff without a matching reserve if
// the semaphore has an initial value or if we have one thread releasing
// a semaphore and another reserving it
if ( !stack.isEmpty()){
if ( stack.peek() == this ){
stack.pop();
}
}
}
}catch( Throwable e ){
try{
Debug.printStackTrace(e);
}catch( Throwable f ){
}
}
}
/*
public void
trace(
boolean _on )
{
trace = _on;
}
*/
protected static class
monSemData
{
protected String class_name;
protected int line_number;
protected
monSemData(
String _class_name,
int _line_number )
{
class_name = _class_name;
line_number = _line_number;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -