public static void unpark__Ljava_lang_Object_2__V (MJIEnv env, int unsafeRef, int objRef) {
ThreadInfo ti = env.getThreadInfo();
if (!ti.isFirstStepInsn()){
System.out.println("No first step");
ThreadInfo tiParked = env.getThreadInfoForObjRef(objRef);
if (tiParked == null || tiParked.isTerminated()){
return;
}
SystemState ss = env.getSystemState();
int permitRef = env.getReferenceField( objRef, "permit");
ElementInfo eiPermit = env.getElementInfo(permitRef);
if (tiParked.getLockObject() == eiPermit){
// note that 'permit' is only used in park/unpark, so there never is more than
// one waiter, which immediately becomes runnable again because it doesn't hold a lock
// (park is a lockfree wait). unpark() therefore has to be a right mover
// and we have to register a ThreadCG here
eiPermit.notifies(ss, ti, false);
ChoiceGenerator<?> cg = env.getSchedulerFactory().createUnparkCG(tiParked);
if (cg != null){
ss.setNextChoiceGenerator(cg);
System.out.println("Repeating invocation");
env.repeatInvocation();
}
} else {
System.out.println("Yes first step");
eiPermit.setBooleanField("blockPark", false);
}
}
}
As you can see (in the underlined line), the execution of the signal can be repeated (env.repeatInvocation()). This repetition will call signal method and it would unpark another thread (in case there are still some). Therefore, it is not unparking every parked thread, but a maximum of two.
In think this is a problem and I am experimenting with it. I did modify removeAndUnpark method. This is my version and it seems to solve the problem:
private void removeAndUnpark(ThreadInfo t) {
ThreadInfo ti = env.getThreadInfo();
if (!ti.isFirstStepInsn()){
System.out.println("Unparking thread: "+t);
getCurrentVersion().removeThreadFromQueue(t);
getCurrentVersion().addRecentlySignalled(t);
unpark(t.getThreadObjectRef());
}
}
Nevertheless, I do not know whether this modification could affect other parts of the extension (since I am not an expert).
Please, find attached a silly application that reproduces the bug. It can produce deadlock, but the important part is that 2 threads are waiting when a third thread makes the signal. Adding System.out.println("Unparking thread: "+t); at the beginning of the method removeAndUnpark you will be able to see it.
I hope everything is clear. Thank you for your time.
Best,
Manuel