62
62
import org .jruby .runtime .builtin .IRubyObject ;
63
63
64
64
import java .util .concurrent .ExecutionException ;
65
+ import java .util .concurrent .Semaphore ;
66
+ import java .util .concurrent .TimeUnit ;
65
67
import java .util .concurrent .atomic .AtomicReference ;
66
68
import java .util .concurrent .locks .Lock ;
67
69
import org .jruby .anno .JRubyMethod ;
@@ -154,6 +156,12 @@ public static enum Status {
154
156
/** The current task blocking a thread, to allow interrupting it in an appropriate way */
155
157
private volatile BlockingTask currentBlockingTask ;
156
158
159
+ /** A function to use to unblock this thread, if possible */
160
+ private Unblocker unblockFunc ;
161
+
162
+ /** Argument to pass to the unblocker */
163
+ private Object unblockArg ;
164
+
157
165
/** The list of locks this thread currently holds, so they can be released on exit */
158
166
private final List <Lock > heldLocks = new Vector <Lock >();
159
167
@@ -927,7 +935,6 @@ public IRubyObject raise(IRubyObject[] args, Block block) {
927
935
* Ruby threads like Timeout's thread.
928
936
*
929
937
* @param args Same args as for Thread#raise
930
- * @param block Same as for Thread#raise
931
938
*/
932
939
public void internalRaise (IRubyObject [] args ) {
933
940
Ruby runtime = getRuntime ();
@@ -1033,6 +1040,15 @@ public static interface BlockingTask {
1033
1040
public void wakeup ();
1034
1041
}
1035
1042
1043
+ public interface Unblocker <Data > {
1044
+ public void wakeup (RubyThread thread , Data self );
1045
+ }
1046
+
1047
+ public interface Task <Data , Return > extends Unblocker <Data > {
1048
+ public Return run (ThreadContext context , Data data ) throws InterruptedException ;
1049
+ public void wakeup (RubyThread thread , Data data );
1050
+ }
1051
+
1036
1052
public static final class SleepTask implements BlockingTask {
1037
1053
private final Object object ;
1038
1054
private final long millis ;
@@ -1057,6 +1073,30 @@ public void wakeup() {
1057
1073
}
1058
1074
}
1059
1075
1076
+ private static final class SleepTask2 implements Task <Object [], Long > {
1077
+ @ Override
1078
+ public Long run (ThreadContext context , Object [] data ) throws InterruptedException {
1079
+ long millis = (Long )data [1 ];
1080
+ int nanos = (Integer )data [2 ];
1081
+
1082
+ long start = System .currentTimeMillis ();
1083
+ // TODO: nano handling?
1084
+ if (millis == 0 ) {
1085
+ ((Semaphore ) data [0 ]).acquire ();
1086
+ } else {
1087
+ ((Semaphore ) data [0 ]).tryAcquire (millis , TimeUnit .MILLISECONDS );
1088
+ }
1089
+ return System .currentTimeMillis () - start ;
1090
+ }
1091
+
1092
+ @ Override
1093
+ public void wakeup (RubyThread thread , Object [] data ) {
1094
+ ((Semaphore )data [0 ]).release ();
1095
+ }
1096
+ }
1097
+
1098
+ private static final Task <Object [], Long > SLEEP_TASK2 = new SleepTask2 ();
1099
+
1060
1100
public void executeBlockingTask (BlockingTask task ) throws InterruptedException {
1061
1101
enterSleep ();
1062
1102
try {
@@ -1070,6 +1110,25 @@ public void executeBlockingTask(BlockingTask task) throws InterruptedException {
1070
1110
}
1071
1111
}
1072
1112
1113
+ public <Data , Return > Return executeTask (ThreadContext context , Data data , Task <Data , Return > task ) throws InterruptedException {
1114
+ try {
1115
+ this .unblockFunc = task ;
1116
+ this .unblockArg = data ;
1117
+
1118
+ // check for interrupt before going into blocking call
1119
+ pollThreadEvents (context );
1120
+
1121
+ enterSleep ();
1122
+
1123
+ return task .run (context , data );
1124
+ } finally {
1125
+ exitSleep ();
1126
+ this .unblockFunc = null ;
1127
+ this .unblockArg = null ;
1128
+ pollThreadEvents (context );
1129
+ }
1130
+ }
1131
+
1073
1132
public void enterSleep () {
1074
1133
status .set (Status .SLEEP );
1075
1134
}
@@ -1351,10 +1410,18 @@ public void interrupt() {
1351
1410
if (iowait != null ) {
1352
1411
iowait .cancel ();
1353
1412
}
1354
-
1355
- BlockingTask task = currentBlockingTask ;
1413
+
1414
+ Unblocker task = this . unblockFunc ;
1356
1415
if (task != null ) {
1357
- task .wakeup ();
1416
+ task .wakeup (this , unblockArg );
1417
+ }
1418
+
1419
+ // deprecated
1420
+ {
1421
+ BlockingTask t = currentBlockingTask ;
1422
+ if (t != null ) {
1423
+ t .wakeup ();
1424
+ }
1358
1425
}
1359
1426
}
1360
1427
private volatile BlockingIO .Condition blockingIO = null ;
0 commit comments