小凡156

博客园 首页 新随笔 联系 订阅 管理
  1 void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
  2 
  3    Thread * Self = THREAD ;
  4 
  5    if (THREAD != _owner) {
  6 
  7      if (THREAD->is_lock_owned((address) _owner)) {
  8 
  9        // Transmute _owner from a BasicLock pointer to a Thread address.
 10 
 11        // We don't need to hold _mutex for this transition.
 12 
 13        // Non-null to Non-null is safe as long as all readers can
 14 
 15        // tolerate either flavor.
 16 
 17        assert (_recursions == 0, "invariant") ;
 18 
 19        _owner = THREAD ;
 20 
 21        _recursions = 0 ;
 22 
 23        OwnerIsThread = 1 ;
 24 
 25      } else {
 26 
 27        // NOTE: we need to handle unbalanced monitor enter/exit
 28 
 29        // in native code by throwing an exception.
 30 
 31        // TODO: Throw an IllegalMonitorStateException ?
 32 
 33        TEVENT (Exit - Throw IMSX) ;
 34 
 35        assert(false, "Non-balanced monitor enter/exit!");
 36 
 37        if (false) {
 38 
 39           THROW(vmSymbols::java_lang_IllegalMonitorStateException());
 40 
 41        }
 42 
 43        return;
 44 
 45      }
 46 
 47    }
 48 
 49    此处是偏向锁逻辑,偏向次数减一后直接返回
 50    if (_recursions != 0) {
 51 
 52      _recursions--;        // this is simple recursive enter
 53 
 54      TEVENT (Inflated exit - recursive) ;
 55 
 56      return ;
 57 
 58    }
 59 
 60 
 61    // Invariant: after setting Responsible=null an thread must execute
 62 
 63    // a MEMBAR or other serializing instruction before fetching EntryList|cxq.
 64 
 65    if ((SyncFlags & 4) == 0) {
 66 
 67       _Responsible = NULL ;
 68 
 69    }
 70 
 71 
 72 #if INCLUDE_TRACE
 73 
 74    // get the owner's thread id for the MonitorEnter event
 75 
 76    // if it is enabled and the thread isn't suspended
 77 
 78    if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
 79 
 80      _previous_owner_tid = SharedRuntime::get_java_tid(Self);
 81 
 82    }
 83 
 84 #endif
 85 
 86 
 87    for (;;) {
 88 
 89       assert (THREAD == _owner, "invariant") ;
 90 
 91 
 92 
 93       if (Knob_ExitPolicy == 0) {
 94 
 95          // release semantics: prior loads and stores from within the critical section
 96 
 97          // must not float (reorder) past the following store that drops the lock.
 98 
 99          // On SPARC that requires MEMBAR #loadstore|#storestore.
100 
101          // But of course in TSO #loadstore|#storestore is not required.
102 
103          // I'd like to write one of the following:
104 
105          // A.  OrderAccess::release() ; _owner = NULL
106 
107          // B.  OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
108 
109          // Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
110 
111          // store into a _dummy variable.  That store is not needed, but can result
112 
113          // in massive wasteful coherency traffic on classic SMP systems.
114 
115          // Instead, I use release_store(), which is implemented as just a simple
116 
117          // ST on x64, x86 and SPARC.
118 
119          OrderAccess::release_store_ptr (&_owner, NULL) ;   // drop the lock
120 
121          OrderAccess::storeload() ;                         // See if we need to wake a successor
122 
123          if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
124 
125             TEVENT (Inflated exit - simple egress) ;
126 
127             return ;
128 
129          }
130 
131          TEVENT (Inflated exit - complex egress) ;
132 
133 
134          // Normally the exiting thread is responsible for ensuring succession,
135 
136          // but if other successors are ready or other entering threads are spinning
137 
138          // then this thread can simply store NULL into _owner and exit without
139 
140          // waking a successor.  The existence of spinners or ready successors
141 
142          // guarantees proper succession (liveness).  Responsibility passes to the
143 
144          // ready or running successors.  The exiting thread delegates the duty.
145 
146          // More precisely, if a successor already exists this thread is absolved
147 
148          // of the responsibility of waking (unparking) one.
149 
150          //
151 
152          // The _succ variable is critical to reducing futile wakeup frequency.
153 
154          // _succ identifies the "heir presumptive" thread that has been made
155 
156          // ready (unparked) but that has not yet run.  We need only one such
157 
158          // successor thread to guarantee progress.
159 
160          // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
161 
162          // section 3.3 "Futile Wakeup Throttling" for details.
163 
164          //
165 
166          // Note that spinners in Enter() also set _succ non-null.
167 
168          // In the current implementation spinners opportunistically set
169 
170          // _succ so that exiting threads might avoid waking a successor.
171 
172          // Another less appealing alternative would be for the exiting thread
173 
174          // to drop the lock and then spin briefly to see if a spinner managed
175 
176          // to acquire the lock.  If so, the exiting thread could exit
177 
178          // immediately without waking a successor, otherwise the exiting
179 
180          // thread would need to dequeue and wake a successor.
181 
182          // (Note that we'd need to make the post-drop spin short, but no
183 
184          // shorter than the worst-case round-trip cache-line migration time.
185 
186          // The dropped lock needs to become visible to the spinner, and then
187 
188          // the acquisition of the lock by the spinner must become visible to
189 
190          // the exiting thread).
191 
192          //
193 
194 
195          // It appears that an heir-presumptive (successor) must be made ready.
196 
197          // Only the current lock owner can manipulate the EntryList or
198 
199          // drain _cxq, so we need to reacquire the lock.  If we fail
200 
201          // to reacquire the lock the responsibility for ensuring succession
202 
203          // falls to the new owner.
204 
205          //
206 
207          if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
208 
209             return ;
210 
211          }
212 
213          TEVENT (Exit - Reacquired) ;
214 
215       } else {
216 
217          if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
218 
219             OrderAccess::release_store_ptr (&_owner, NULL) ;   // drop the lock
220 
221             OrderAccess::storeload() ;
222 
223             // Ratify the previously observed values.
224 
225             if (_cxq == NULL || _succ != NULL) {
226 
227                 TEVENT (Inflated exit - simple egress) ;
228 
229                 return ;
230 
231             }
232 
233 
234             // inopportune interleaving -- the exiting thread (this thread)
235 
236             // in the fast-exit path raced an entering thread in the slow-enter
237 
238             // path.
239 
240             // We have two choices:
241 
242             // A.  Try to reacquire the lock.
243 
244             //     If the CAS() fails return immediately, otherwise
245 
246             //     we either restart/rerun the exit operation, or simply
247 
248             //     fall-through into the code below which wakes a successor.
249 
250             // B.  If the elements forming the EntryList|cxq are TSM
251 
252             //     we could simply unpark() the lead thread and return
253 
254             //     without having set _succ.
255 
256             if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
257 
258                TEVENT (Inflated exit - reacquired succeeded) ;
259 
260                return ;
261 
262             }
263 
264             TEVENT (Inflated exit - reacquired failed) ;
265 
266          } else {
267 
268             TEVENT (Inflated exit - complex egress) ;
269 
270          }
271 
272       }
273 
274 
275       guarantee (_owner == THREAD, "invariant") ;
276 
277 
278       ObjectWaiter * w = NULL ;
279 
280       int QMode = Knob_QMode ;
281 
282      QMode = 2,并且_cxq非空:取_cxq队列排头位置的ObjectWaiter对象,调用ExitEpilog方法,该方法会唤醒ObjectWaiter对象的线程,此处会立即返回,后面的代码不会执行了
283       if (QMode == 2 && _cxq != NULL) {
284 
285           // QMode == 2 : cxq has precedence over EntryList.
286 
287           // Try to directly wake a successor from the cxq.
288 
289           // If successful, the successor will need to unlink itself from cxq.
290 
291           w = _cxq ;
292 
293           assert (w != NULL, "invariant") ;
294 
295           assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
296 
297           ExitEpilog (Self, w) ;
298 
299           return ;
300 
301       }
302 
303     QMode = 3,并且_cxq非空:把_cxq队列首元素放入_EntryList的尾部;
304       if (QMode == 3 && _cxq != NULL) {
305 
306           // Aggressively drain cxq into EntryList at the first opportunity.
307 
308           // This policy ensure that recently-run threads live at the head of EntryList.
309 
310           // Drain _cxq into EntryList - bulk transfer.
311 
312           // First, detach _cxq.
313 
314           // The following loop is tantamount to: w = swap (&cxq, NULL)
315 
316           w = _cxq ;
317 
318           for (;;) {
319 
320              assert (w != NULL, "Invariant") ;
321 
322              ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
323 
324              if (u == w) break ;
325 
326              w = u ;
327 
328           }
329 
330           assert (w != NULL              , "invariant") ;
331 
332 
333           ObjectWaiter * q = NULL ;
334 
335           ObjectWaiter * p ;
336 
337           for (p = w ; p != NULL ; p = p->_next) {
338 
339               guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
340 
341               p->TState = ObjectWaiter::TS_ENTER ;
342 
343               p->_prev = q ;
344 
345               q = p ;
346 
347           }
348 
349 
350           // Append the RATs to the EntryList
351 
352           // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
353 
354           ObjectWaiter * Tail ;
355 
356           for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
357 
358           if (Tail == NULL) {
359 
360               _EntryList = w ;
361 
362           } else {
363 
364               Tail->_next = w ;
365 
366               w->_prev = Tail ;
367 
368           }
369 
370 
371           // Fall thru into code that tries to wake a successor from EntryList
372 
373       }
374 
375     Mode = 4,并且_cxq非空:把_cxq队列首元素放入_EntryList的头部;
376       if (QMode == 4 && _cxq != NULL) {
377 
378           // Aggressively drain cxq into EntryList at the first opportunity.
379 
380           // This policy ensure that recently-run threads live at the head of EntryList.
381 
382 
383           // Drain _cxq into EntryList - bulk transfer.
384 
385           // First, detach _cxq.
386 
387           // The following loop is tantamount to: w = swap (&cxq, NULL)
388 
389           w = _cxq ;
390 
391           for (;;) {
392 
393              assert (w != NULL, "Invariant") ;
394 
395              ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
396 
397              if (u == w) break ;
398 
399              w = u ;
400 
401           }
402 
403           assert (w != NULL              , "invariant") ;
404 
405 
406           ObjectWaiter * q = NULL ;
407 
408           ObjectWaiter * p ;
409 
410           for (p = w ; p != NULL ; p = p->_next) {
411 
412               guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
413 
414               p->TState = ObjectWaiter::TS_ENTER ;
415 
416               p->_prev = q ;
417 
418               q = p ;
419 
420           }
421 
422 
423           // Prepend the RATs to the EntryList
424 
425           if (_EntryList != NULL) {
426 
427               q->_next = _EntryList ;
428 
429               _EntryList->_prev = q ;
430 
431           }
432 
433           _EntryList = w ;
434 
435 
436           // Fall thru into code that tries to wake a successor from EntryList
437 
438       }
439 
440 
441       w = _EntryList  ;
442 
443       if (w != NULL) {
444 
445           // I'd like to write: guarantee (w->_thread != Self).
446 
447           // But in practice an exiting thread may find itself on the EntryList.
448 
449           // Lets say thread T1 calls O.wait().  Wait() enqueues T1 on O's waitset and
450 
451           // then calls exit().  Exit release the lock by setting O._owner to NULL.
452 
453           // Lets say T1 then stalls.  T2 acquires O and calls O.notify().  The
454 
455           // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
456 
457           // release the lock "O".  T2 resumes immediately after the ST of null into
458 
459           // _owner, above.  T2 notices that the EntryList is populated, so it
460 
461           // reacquires the lock and then finds itself on the EntryList.
462 
463           // Given all that, we have to tolerate the circumstance where "w" is
464 
465           // associated with Self.
466 
467           assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
468 
469           ExitEpilog (Self, w) ;
470 
471           return ;
472 
473       }
474 
475 
476       // If we find that both _cxq and EntryList are null then just
477 
478       // re-run the exit protocol from the top.
479 
480       w = _cxq ;
481 
482       if (w == NULL) continue ;
483 
484 
485       // Drain _cxq into EntryList - bulk transfer.
486 
487       // First, detach _cxq.
488 
489       // The following loop is tantamount to: w = swap (&cxq, NULL)
490 
491       for (;;) {
492 
493           assert (w != NULL, "Invariant") ;
494 
495           ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
496 
497           if (u == w) break ;
498 
499           w = u ;
500 
501       }
502 
503       TEVENT (Inflated exit - drain cxq into EntryList) ;
504 
505 
506       assert (w != NULL              , "invariant") ;
507 
508       assert (_EntryList  == NULL    , "invariant") ;
509 
510 
511       // Convert the LIFO SLL anchored by _cxq into a DLL.
512 
513       // The list reorganization step operates in O(LENGTH(w)) time.
514 
515       // It's critical that this step operate quickly as
516 
517       // "Self" still holds the outer-lock, restricting parallelism
518 
519       // and effectively lengthening the critical section.
520 
521       // Invariant: s chases t chases u.
522 
523       // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
524 
525       // we have faster access to the tail.
526 
527 
528       if (QMode == 1) {
529 
530          // QMode == 1 : drain cxq to EntryList, reversing order
531 
532          // We also reverse the order of the list.
533 
534          ObjectWaiter * s = NULL ;
535 
536          ObjectWaiter * t = w ;
537 
538          ObjectWaiter * u = NULL ;
539 
540          while (t != NULL) {
541 
542              guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
543 
544              t->TState = ObjectWaiter::TS_ENTER ;
545 
546              u = t->_next ;
547 
548              t->_prev = u ;
549 
550              t->_next = s ;
551 
552              s = t;
553 
554              t = u ;
555 
556          }
557 
558          _EntryList  = s ;
559 
560          assert (s != NULL, "invariant") ;
561 
562       } else {
563 
564          // QMode == 0 or QMode == 2
565 
566          _EntryList = w ;
567 
568          ObjectWaiter * q = NULL ;
569 
570          ObjectWaiter * p ;
571 
572          for (p = w ; p != NULL ; p = p->_next) {
573 
574              guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
575 
576              p->TState = ObjectWaiter::TS_ENTER ;
577 
578              p->_prev = q ;
579 
580              q = p ;
581 
582          }
583 
584       }
585 
586 
587       // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
588 
589       // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
590 
591 
592       // See if we can abdicate to a spinner instead of waking a thread.
593 
594       // A primary goal of the implementation is to reduce the
595 
596       // context-switch rate.
597 
598       if (_succ != NULL) continue;
599 
600 
601       w = _EntryList  ;
602 
603       if (w != NULL) {
604 
605           guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
606 
607           ExitEpilog (Self, w) ;
608 
609           return ;
610 
611       }
612 
613    }
614 
615 }

 

总结释放锁内容:

1. 偏向锁逻辑;

2. 根据QMode的不同,将ObjectWaiter从_cxq或者_EntryList中取出后唤醒;

3. 唤醒的元素会继续执行挂起前的代码,按照我们之前的分析,线程唤醒后,就会通过CAS去竞争锁;

  1. 根据QMode的不同,将ObjectWaiter从_cxq或者_EntryList中取出后唤醒;
posted on 2019-11-10 16:16  小凡156  阅读(277)  评论(0编辑  收藏  举报