1036 * @return next state, or INTERRUPTED |
1034 * @return next state, or INTERRUPTED |
1037 */ |
1035 */ |
1038 private long acquireWrite(boolean interruptible, long deadline) { |
1036 private long acquireWrite(boolean interruptible, long deadline) { |
1039 WNode node = null, p; |
1037 WNode node = null, p; |
1040 for (int spins = -1;;) { // spin while enqueuing |
1038 for (int spins = -1;;) { // spin while enqueuing |
1041 long s, ns; |
1039 long m, s, ns; |
1042 if (((s = state) & ABITS) == 0L) { |
1040 if ((m = (s = state) & ABITS) == 0L) { |
1043 if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) |
1041 if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) |
1044 return ns; |
1042 return ns; |
1045 } |
1043 } |
|
1044 else if (spins < 0) |
|
1045 spins = (m == WBIT && wtail == whead) ? SPINS : 0; |
1046 else if (spins > 0) { |
1046 else if (spins > 0) { |
1047 if (LockSupport.nextSecondarySeed() >= 0) |
1047 if (LockSupport.nextSecondarySeed() >= 0) |
1048 --spins; |
1048 --spins; |
1049 } |
1049 } |
1050 else if ((p = wtail) == null) { // initialize queue |
1050 else if ((p = wtail) == null) { // initialize queue |
1051 WNode h = new WNode(WMODE, null); |
1051 WNode hd = new WNode(WMODE, null); |
1052 if (U.compareAndSwapObject(this, WHEAD, null, h)) |
1052 if (U.compareAndSwapObject(this, WHEAD, null, hd)) |
1053 wtail = h; |
1053 wtail = hd; |
1054 } |
1054 } |
1055 else if (spins < 0) |
|
1056 spins = (p == whead) ? SPINS : 0; |
|
1057 else if (node == null) |
1055 else if (node == null) |
1058 node = new WNode(WMODE, p); |
1056 node = new WNode(WMODE, p); |
1059 else if (node.prev != p) |
1057 else if (node.prev != p) |
1060 node.prev = p; |
1058 node.prev = p; |
1061 else if (U.compareAndSwapObject(this, WTAIL, p, node)) { |
1059 else if (U.compareAndSwapObject(this, WTAIL, p, node)) { |
1062 p.next = node; |
1060 p.next = node; |
1063 break; |
1061 break; |
1064 } |
1062 } |
1065 } |
1063 } |
1066 |
1064 |
1067 for (int spins = SPINS;;) { |
1065 for (int spins = -1;;) { |
1068 WNode np, pp; int ps; long s, ns; Thread w; |
1066 WNode h, np, pp; int ps; |
1069 while ((np = node.prev) != p && np != null) |
1067 if ((h = whead) == p) { |
1070 (p = np).next = node; // stale |
1068 if (spins < 0) |
1071 if (whead == p) { |
1069 spins = HEAD_SPINS; |
|
1070 else if (spins < MAX_HEAD_SPINS) |
|
1071 spins <<= 1; |
1072 for (int k = spins;;) { // spin at head |
1072 for (int k = spins;;) { // spin at head |
|
1073 long s, ns; |
1073 if (((s = state) & ABITS) == 0L) { |
1074 if (((s = state) & ABITS) == 0L) { |
1074 if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) { |
1075 if (U.compareAndSwapLong(this, STATE, s, |
|
1076 ns = s + WBIT)) { |
1075 whead = node; |
1077 whead = node; |
1076 node.prev = null; |
1078 node.prev = null; |
1077 return ns; |
1079 return ns; |
1078 } |
1080 } |
1079 } |
1081 } |
1080 else if (LockSupport.nextSecondarySeed() >= 0 && |
1082 else if (LockSupport.nextSecondarySeed() >= 0 && |
1081 --k <= 0) |
1083 --k <= 0) |
1082 break; |
1084 break; |
1083 } |
1085 } |
1084 if (spins < MAX_HEAD_SPINS) |
1086 } |
1085 spins <<= 1; |
1087 else if (h != null) { // help release stale waiters |
1086 } |
1088 WNode c; Thread w; |
1087 if ((ps = p.status) == 0) |
1089 while ((c = h.cowait) != null) { |
1088 U.compareAndSwapInt(p, WSTATUS, 0, WAITING); |
1090 if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && |
1089 else if (ps == CANCELLED) { |
1091 (w = c.thread) != null) |
1090 if ((pp = p.prev) != null) { |
1092 U.unpark(w); |
1091 node.prev = pp; |
1093 } |
1092 pp.next = node; |
1094 } |
1093 } |
1095 if (whead == h) { |
1094 } |
1096 if ((np = node.prev) != p) { |
1095 else { |
1097 if (np != null) |
1096 long time; // 0 argument to park means no timeout |
1098 (p = np).next = node; // stale |
1097 if (deadline == 0L) |
1099 } |
1098 time = 0L; |
1100 else if ((ps = p.status) == 0) |
1099 else if ((time = deadline - System.nanoTime()) <= 0L) |
1101 U.compareAndSwapInt(p, WSTATUS, 0, WAITING); |
1100 return cancelWaiter(node, node, false); |
1102 else if (ps == CANCELLED) { |
1101 Thread wt = Thread.currentThread(); |
1103 if ((pp = p.prev) != null) { |
1102 U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park |
1104 node.prev = pp; |
1103 node.thread = wt; |
1105 pp.next = node; |
1104 if (node.prev == p && p.status == WAITING && // recheck |
1106 } |
1105 (p != whead || (state & ABITS) != 0L)) |
1107 } |
1106 U.park(false, time); |
1108 else { |
1107 node.thread = null; |
1109 long time; // 0 argument to park means no timeout |
1108 U.putObject(wt, PARKBLOCKER, null); |
1110 if (deadline == 0L) |
1109 if (interruptible && Thread.interrupted()) |
1111 time = 0L; |
1110 return cancelWaiter(node, node, true); |
1112 else if ((time = deadline - System.nanoTime()) <= 0L) |
|
1113 return cancelWaiter(node, node, false); |
|
1114 Thread wt = Thread.currentThread(); |
|
1115 U.putObject(wt, PARKBLOCKER, this); |
|
1116 node.thread = wt; |
|
1117 if (p.status < 0 && (p != h || (state & ABITS) != 0L) && |
|
1118 whead == h && node.prev == p) |
|
1119 U.park(false, time); // emulate LockSupport.park |
|
1120 node.thread = null; |
|
1121 U.putObject(wt, PARKBLOCKER, null); |
|
1122 if (interruptible && Thread.interrupted()) |
|
1123 return cancelWaiter(node, node, true); |
|
1124 } |
1111 } |
1125 } |
1112 } |
1126 } |
1113 } |
1127 } |
1114 |
1128 |
1115 /** |
1129 /** |
1120 * @param deadline if nonzero, the System.nanoTime value to timeout |
1134 * @param deadline if nonzero, the System.nanoTime value to timeout |
1121 * at (and return zero) |
1135 * at (and return zero) |
1122 * @return next state, or INTERRUPTED |
1136 * @return next state, or INTERRUPTED |
1123 */ |
1137 */ |
1124 private long acquireRead(boolean interruptible, long deadline) { |
1138 private long acquireRead(boolean interruptible, long deadline) { |
1125 WNode node = null, group = null, p; |
1139 WNode node = null, p; |
1126 for (int spins = -1;;) { |
1140 for (int spins = -1;;) { |
1127 for (;;) { |
1141 WNode h; |
1128 long s, m, ns; WNode h, q; Thread w; // anti-barging guard |
1142 if ((h = whead) == (p = wtail)) { |
1129 if (group == null && (h = whead) != null && |
1143 for (long m, s, ns;;) { |
1130 (q = h.next) != null && q.mode != RMODE) |
1144 if ((m = (s = state) & ABITS) < RFULL ? |
1131 break; |
1145 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : |
1132 if ((m = (s = state) & ABITS) < RFULL ? |
1146 (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) |
1133 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : |
1147 return ns; |
1134 (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { |
1148 else if (m >= WBIT) { |
1135 if (group != null) { // help release others |
1149 if (spins > 0) { |
1136 for (WNode r = group;;) { |
1150 if (LockSupport.nextSecondarySeed() >= 0) |
1137 if ((w = r.thread) != null) { |
1151 --spins; |
1138 r.thread = null; |
1152 } |
1139 U.unpark(w); |
1153 else { |
|
1154 if (spins == 0) { |
|
1155 WNode nh = whead, np = wtail; |
|
1156 if ((nh == h && np == p) || (h = nh) != (p = np)) |
|
1157 break; |
1140 } |
1158 } |
1141 if ((r = group.cowait) == null) |
1159 spins = SPINS; |
1142 break; |
|
1143 U.compareAndSwapObject(group, WCOWAIT, r, r.cowait); |
|
1144 } |
1160 } |
1145 } |
1161 } |
1146 return ns; |
1162 } |
1147 } |
1163 } |
1148 if (m >= WBIT) |
1164 if (p == null) { // initialize queue |
|
1165 WNode hd = new WNode(WMODE, null); |
|
1166 if (U.compareAndSwapObject(this, WHEAD, null, hd)) |
|
1167 wtail = hd; |
|
1168 } |
|
1169 else if (node == null) |
|
1170 node = new WNode(RMODE, p); |
|
1171 else if (h == p || p.mode != RMODE) { |
|
1172 if (node.prev != p) |
|
1173 node.prev = p; |
|
1174 else if (U.compareAndSwapObject(this, WTAIL, p, node)) { |
|
1175 p.next = node; |
1149 break; |
1176 break; |
1150 } |
1177 } |
1151 if (spins > 0) { |
1178 } |
1152 if (LockSupport.nextSecondarySeed() >= 0) |
1179 else if (!U.compareAndSwapObject(p, WCOWAIT, |
1153 --spins; |
1180 node.cowait = p.cowait, node)) |
1154 } |
1181 node.cowait = null; |
1155 else if ((p = wtail) == null) { |
1182 else { |
1156 WNode h = new WNode(WMODE, null); |
1183 for (;;) { |
1157 if (U.compareAndSwapObject(this, WHEAD, null, h)) |
1184 WNode pp, c; Thread w; |
1158 wtail = h; |
1185 if ((h = whead) != null && (c = h.cowait) != null && |
1159 } |
1186 U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && |
1160 else if (spins < 0) |
1187 (w = c.thread) != null) // help release |
1161 spins = (p == whead) ? SPINS : 0; |
1188 U.unpark(w); |
1162 else if (node == null) |
1189 if (h == (pp = p.prev) || h == p || pp == null) { |
1163 node = new WNode(WMODE, p); |
1190 long m, s, ns; |
1164 else if (node.prev != p) |
1191 do { |
1165 node.prev = p; |
1192 if ((m = (s = state) & ABITS) < RFULL ? |
1166 else if (p.mode == RMODE && p != whead) { |
1193 U.compareAndSwapLong(this, STATE, s, |
1167 WNode pp = p.prev; // become co-waiter with group p |
1194 ns = s + RUNIT) : |
1168 if (pp != null && p == wtail && |
1195 (m < WBIT && |
1169 U.compareAndSwapObject(p, WCOWAIT, |
1196 (ns = tryIncReaderOverflow(s)) != 0L)) |
1170 node.cowait = p.cowait, node)) { |
1197 return ns; |
1171 node.thread = Thread.currentThread(); |
1198 } while (m < WBIT); |
1172 for (long time;;) { |
1199 } |
|
1200 if (whead == h && p.prev == pp) { |
|
1201 long time; |
|
1202 if (pp == null || h == p || p.status > 0) { |
|
1203 node = null; // throw away |
|
1204 break; |
|
1205 } |
1173 if (deadline == 0L) |
1206 if (deadline == 0L) |
1174 time = 0L; |
1207 time = 0L; |
1175 else if ((time = deadline - System.nanoTime()) <= 0L) |
1208 else if ((time = deadline - System.nanoTime()) <= 0L) |
1176 return cancelWaiter(node, p, false); |
1209 return cancelWaiter(node, p, false); |
1177 if (node.thread == null) |
|
1178 break; |
|
1179 if (p.prev != pp || p.status == CANCELLED || |
|
1180 p == whead || p.prev != pp) { |
|
1181 node.thread = null; |
|
1182 break; |
|
1183 } |
|
1184 Thread wt = Thread.currentThread(); |
1210 Thread wt = Thread.currentThread(); |
1185 U.putObject(wt, PARKBLOCKER, this); |
1211 U.putObject(wt, PARKBLOCKER, this); |
1186 if (node.thread == null) // must recheck |
1212 node.thread = wt; |
1187 break; |
1213 if ((h != pp || (state & ABITS) == WBIT) && |
1188 U.park(false, time); |
1214 whead == h && p.prev == pp) |
|
1215 U.park(false, time); |
|
1216 node.thread = null; |
1189 U.putObject(wt, PARKBLOCKER, null); |
1217 U.putObject(wt, PARKBLOCKER, null); |
1190 if (interruptible && Thread.interrupted()) |
1218 if (interruptible && Thread.interrupted()) |
1191 return cancelWaiter(node, p, true); |
1219 return cancelWaiter(node, p, true); |
1192 } |
1220 } |
1193 group = p; |
1221 } |
1194 } |
1222 } |
1195 node = null; // throw away |
1223 } |
1196 } |
1224 |
1197 else if (U.compareAndSwapObject(this, WTAIL, p, node)) { |
1225 for (int spins = -1;;) { |
1198 p.next = node; |
1226 WNode h, np, pp; int ps; |
1199 break; |
1227 if ((h = whead) == p) { |
1200 } |
1228 if (spins < 0) |
1201 } |
1229 spins = HEAD_SPINS; |
1202 |
1230 else if (spins < MAX_HEAD_SPINS) |
1203 for (int spins = SPINS;;) { |
1231 spins <<= 1; |
1204 WNode np, pp, r; int ps; long m, s, ns; Thread w; |
1232 for (int k = spins;;) { // spin at head |
1205 while ((np = node.prev) != p && np != null) |
1233 long m, s, ns; |
1206 (p = np).next = node; |
1234 if ((m = (s = state) & ABITS) < RFULL ? |
1207 if (whead == p) { |
1235 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : |
1208 for (int k = spins;;) { |
1236 (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { |
1209 if ((m = (s = state) & ABITS) != WBIT) { |
1237 WNode c; Thread w; |
1210 if (m < RFULL ? |
1238 whead = node; |
1211 U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT): |
1239 node.prev = null; |
1212 (ns = tryIncReaderOverflow(s)) != 0L) { |
1240 while ((c = node.cowait) != null) { |
1213 whead = node; |
1241 if (U.compareAndSwapObject(node, WCOWAIT, |
1214 node.prev = null; |
1242 c, c.cowait) && |
1215 while ((r = node.cowait) != null) { |
1243 (w = c.thread) != null) |
1216 if (U.compareAndSwapObject(node, WCOWAIT, |
1244 U.unpark(w); |
1217 r, r.cowait) && |
|
1218 (w = r.thread) != null) { |
|
1219 r.thread = null; |
|
1220 U.unpark(w); // release co-waiter |
|
1221 } |
|
1222 } |
|
1223 return ns; |
|
1224 } |
1245 } |
|
1246 return ns; |
1225 } |
1247 } |
1226 else if (LockSupport.nextSecondarySeed() >= 0 && |
1248 else if (m >= WBIT && |
1227 --k <= 0) |
1249 LockSupport.nextSecondarySeed() >= 0 && --k <= 0) |
1228 break; |
1250 break; |
1229 } |
1251 } |
1230 if (spins < MAX_HEAD_SPINS) |
1252 } |
1231 spins <<= 1; |
1253 else if (h != null) { |
1232 } |
1254 WNode c; Thread w; |
1233 if ((ps = p.status) == 0) |
1255 while ((c = h.cowait) != null) { |
1234 U.compareAndSwapInt(p, WSTATUS, 0, WAITING); |
1256 if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && |
1235 else if (ps == CANCELLED) { |
1257 (w = c.thread) != null) |
1236 if ((pp = p.prev) != null) { |
1258 U.unpark(w); |
1237 node.prev = pp; |
1259 } |
1238 pp.next = node; |
1260 } |
1239 } |
1261 if (whead == h) { |
1240 } |
1262 if ((np = node.prev) != p) { |
1241 else { |
1263 if (np != null) |
1242 long time; |
1264 (p = np).next = node; // stale |
1243 if (deadline == 0L) |
1265 } |
1244 time = 0L; |
1266 else if ((ps = p.status) == 0) |
1245 else if ((time = deadline - System.nanoTime()) <= 0L) |
1267 U.compareAndSwapInt(p, WSTATUS, 0, WAITING); |
1246 return cancelWaiter(node, node, false); |
1268 else if (ps == CANCELLED) { |
1247 Thread wt = Thread.currentThread(); |
1269 if ((pp = p.prev) != null) { |
1248 U.putObject(wt, PARKBLOCKER, this); |
1270 node.prev = pp; |
1249 node.thread = wt; |
1271 pp.next = node; |
1250 if (node.prev == p && p.status == WAITING && |
1272 } |
1251 (p != whead || (state & ABITS) != WBIT)) |
1273 } |
1252 U.park(false, time); |
1274 else { |
1253 node.thread = null; |
1275 long time; |
1254 U.putObject(wt, PARKBLOCKER, null); |
1276 if (deadline == 0L) |
1255 if (interruptible && Thread.interrupted()) |
1277 time = 0L; |
1256 return cancelWaiter(node, node, true); |
1278 else if ((time = deadline - System.nanoTime()) <= 0L) |
|
1279 return cancelWaiter(node, node, false); |
|
1280 Thread wt = Thread.currentThread(); |
|
1281 U.putObject(wt, PARKBLOCKER, this); |
|
1282 node.thread = wt; |
|
1283 if (p.status < 0 && |
|
1284 (p != h || (state & ABITS) == WBIT) && |
|
1285 whead == h && node.prev == p) |
|
1286 U.park(false, time); |
|
1287 node.thread = null; |
|
1288 U.putObject(wt, PARKBLOCKER, null); |
|
1289 if (interruptible && Thread.interrupted()) |
|
1290 return cancelWaiter(node, node, true); |
|
1291 } |
1257 } |
1292 } |
1258 } |
1293 } |
1259 } |
1294 } |
1260 |
1295 |
1261 /** |
1296 /** |
1276 */ |
1311 */ |
1277 private long cancelWaiter(WNode node, WNode group, boolean interrupted) { |
1312 private long cancelWaiter(WNode node, WNode group, boolean interrupted) { |
1278 if (node != null && group != null) { |
1313 if (node != null && group != null) { |
1279 Thread w; |
1314 Thread w; |
1280 node.status = CANCELLED; |
1315 node.status = CANCELLED; |
1281 node.thread = null; |
|
1282 // unsplice cancelled nodes from group |
1316 // unsplice cancelled nodes from group |
1283 for (WNode p = group, q; (q = p.cowait) != null;) { |
1317 for (WNode p = group, q; (q = p.cowait) != null;) { |
1284 if (q.status == CANCELLED) |
1318 if (q.status == CANCELLED) { |
1285 U.compareAndSwapObject(p, WNEXT, q, q.next); |
1319 U.compareAndSwapObject(p, WCOWAIT, q, q.cowait); |
|
1320 p = group; // restart |
|
1321 } |
1286 else |
1322 else |
1287 p = q; |
1323 p = q; |
1288 } |
1324 } |
1289 if (group == node) { |
1325 if (group == node) { |
1290 WNode r; // detach and wake up uncancelled co-waiters |
1326 for (WNode r = group.cowait; r != null; r = r.cowait) { |
1291 while ((r = node.cowait) != null) { |
1327 if ((w = r.thread) != null) |
1292 if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && |
1328 U.unpark(w); // wake up uncancelled co-waiters |
1293 (w = r.thread) != null) { |
|
1294 r.thread = null; |
|
1295 U.unpark(w); |
|
1296 } |
|
1297 } |
1329 } |
1298 for (WNode pred = node.prev; pred != null; ) { // unsplice |
1330 for (WNode pred = node.prev; pred != null; ) { // unsplice |
1299 WNode succ, pp; // find valid successor |
1331 WNode succ, pp; // find valid successor |
1300 while ((succ = node.next) == null || |
1332 while ((succ = node.next) == null || |
1301 succ.status == CANCELLED) { |
1333 succ.status == CANCELLED) { |