| 3267 | } |
| 3268 | }, |
| 3269 | waitOn(thread, obj, timeout) { |
| 3270 | const monitor = obj.__monitor || (obj.__monitor = this.createMonitor()); |
| 3271 | if (monitor.owner !== thread.id) { |
| 3272 | throw new Error("IllegalMonitorStateException"); |
| 3273 | } |
| 3274 | const reentryCount = monitor.count; |
| 3275 | monitor.owner = null; |
| 3276 | monitor.count = 0; |
| 3277 | // Releasing the monitor for ``wait`` must also drain the head of |
| 3278 | // the entrants queue, identical to ``monitorExit``. Otherwise any |
| 3279 | // thread parked on this monitor stays stuck forever even after |
| 3280 | // the holder calls wait() and (eventually) gets notified -- |
| 3281 | // ownership goes back to the waker, never to the queued entrant. |
| 3282 | // This is the asymmetry that hung lifecycle.start: EDT acquired |
| 3283 | // Display.lock, called wait, didn't promote the main thread ( |
| 3284 | // queued on entrants from invokeAndBlock's first synchronized |
| 3285 | // block), and the runtime sat with owner=null + entrants=1 |
| 3286 | // forever. |
| 3287 | if (monitor.entrants.length) { |
| 3288 | const next = monitor.entrants.shift(); |
| 3289 | monitor.owner = next.thread.id; |
| 3290 | monitor.count = next.reentryCount; |
| 3291 | this.enqueue(next.thread, next.resumeValue); |
| 3292 | } |
| 3293 | return { op: "wait", monitor: obj, timeout: _LtoNum(timeout) | 0, reentryCount: reentryCount }; |
| 3294 | }, |
| 3295 | notifyOne(obj) { |
| 3296 | const monitor = obj.__monitor || (obj.__monitor = this.createMonitor()); |
| 3297 | const waiter = monitor.waiters.shift(); |