@@ -16,7 +16,8 @@ struct qnode {
16
16
struct qnode * next ;
17
17
struct qspinlock * lock ;
18
18
int cpu ;
19
- int yield_cpu ;
19
+ u8 sleepy ; /* 1 if the previous vCPU was preempted or
20
+ * if the previous node was sleepy */
20
21
u8 locked ; /* 1 if lock acquired */
21
22
};
22
23
@@ -349,7 +350,7 @@ static __always_inline bool yield_head_to_locked_owner(struct qspinlock *lock, u
349
350
return __yield_to_locked_owner (lock , val , paravirt , mustq );
350
351
}
351
352
352
- static __always_inline void propagate_yield_cpu (struct qnode * node , u32 val , int * set_yield_cpu , bool paravirt )
353
+ static __always_inline void propagate_sleepy (struct qnode * node , u32 val , bool * set_sleepy , bool paravirt )
353
354
{
354
355
struct qnode * next ;
355
356
int owner ;
@@ -358,29 +359,24 @@ static __always_inline void propagate_yield_cpu(struct qnode *node, u32 val, int
358
359
return ;
359
360
if (!pv_yield_propagate_owner )
360
361
return ;
361
-
362
- owner = get_owner_cpu (val );
363
- if (* set_yield_cpu == owner )
362
+ if (* set_sleepy )
364
363
return ;
365
364
366
365
next = READ_ONCE (node -> next );
367
366
if (!next )
368
367
return ;
369
368
369
+ owner = get_owner_cpu (val );
370
370
if (vcpu_is_preempted (owner )) {
371
- next -> yield_cpu = owner ;
372
- * set_yield_cpu = owner ;
373
- } else if (* set_yield_cpu != -1 ) {
374
- next -> yield_cpu = owner ;
375
- * set_yield_cpu = owner ;
371
+ next -> sleepy = 1 ;
372
+ * set_sleepy = true;
376
373
}
377
374
}
378
375
379
376
/* Called inside spin_begin() */
380
377
static __always_inline bool yield_to_prev (struct qspinlock * lock , struct qnode * node , int prev_cpu , bool paravirt )
381
378
{
382
379
u32 yield_count ;
383
- int yield_cpu ;
384
380
bool preempted = false;
385
381
386
382
if (!paravirt )
@@ -389,36 +385,32 @@ static __always_inline bool yield_to_prev(struct qspinlock *lock, struct qnode *
389
385
if (!pv_yield_propagate_owner )
390
386
goto yield_prev ;
391
387
392
- yield_cpu = READ_ONCE (node -> yield_cpu );
393
- if (yield_cpu == -1 ) {
394
- /* Propagate back the -1 CPU */
395
- if (node -> next && node -> next -> yield_cpu != -1 )
396
- node -> next -> yield_cpu = yield_cpu ;
388
+ if (!READ_ONCE (node -> sleepy )) {
389
+ /* Propagate back sleepy==false */
390
+ if (node -> next && node -> next -> sleepy )
391
+ node -> next -> sleepy = 0 ;
397
392
goto yield_prev ;
398
- }
399
-
400
- yield_count = yield_count_of ( yield_cpu );
401
- if (( yield_count & 1 ) == 0 )
402
- goto yield_prev ; /* owner vcpu is running */
403
-
404
- if ( get_owner_cpu ( READ_ONCE ( lock -> val )) != yield_cpu )
405
- goto yield_prev ; /* re-sample lock owner */
406
-
407
- spin_end ();
408
-
409
- preempted = true;
410
- seen_sleepy_node ();
411
-
412
- smp_rmb ();
393
+ } else {
394
+ u32 val = READ_ONCE ( lock -> val );
395
+
396
+ if (val & _Q_LOCKED_VAL ) {
397
+ if ( node -> next && ! node -> next -> sleepy ) {
398
+ /*
399
+ * Propagate sleepy to next waiter. Only if
400
+ * owner is preempted, which allows the queue
401
+ * to become "non-sleepy" if vCPU preemption
402
+ * ceases to occur, even if the lock remains
403
+ * highly contended.
404
+ */
405
+ if ( vcpu_is_preempted ( get_owner_cpu ( val )))
406
+ node -> next -> sleepy = 1 ;
407
+ }
413
408
414
- if (yield_cpu == node -> yield_cpu ) {
415
- if (node -> next && node -> next -> yield_cpu != yield_cpu )
416
- node -> next -> yield_cpu = yield_cpu ;
417
- yield_to_preempted (yield_cpu , yield_count );
418
- spin_begin ();
419
- return preempted ;
409
+ preempted = yield_to_locked_owner (lock , val , paravirt );
410
+ if (preempted )
411
+ return preempted ;
412
+ }
420
413
}
421
- spin_begin ();
422
414
423
415
yield_prev :
424
416
if (!pv_yield_prev )
@@ -541,7 +533,7 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b
541
533
bool sleepy = false;
542
534
bool mustq = false;
543
535
int idx ;
544
- int set_yield_cpu = -1 ;
536
+ bool set_sleepy = false ;
545
537
int iters = 0 ;
546
538
547
539
BUILD_BUG_ON (CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS ));
@@ -565,7 +557,7 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b
565
557
node -> next = NULL ;
566
558
node -> lock = lock ;
567
559
node -> cpu = smp_processor_id ();
568
- node -> yield_cpu = -1 ;
560
+ node -> sleepy = 0 ;
569
561
node -> locked = 0 ;
570
562
571
563
tail = encode_tail_cpu (node -> cpu );
@@ -599,9 +591,9 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b
599
591
spec_barrier ();
600
592
spin_end ();
601
593
602
- /* Clear out stale propagated yield_cpu */
603
- if (paravirt && pv_yield_propagate_owner && node -> yield_cpu != -1 )
604
- node -> yield_cpu = -1 ;
594
+ /* Clear out stale propagated sleepy */
595
+ if (paravirt && pv_yield_propagate_owner && node -> sleepy )
596
+ node -> sleepy = 0 ;
605
597
606
598
smp_rmb (); /* acquire barrier for the mcs lock */
607
599
@@ -644,7 +636,7 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b
644
636
}
645
637
}
646
638
647
- propagate_yield_cpu (node , val , & set_yield_cpu , paravirt );
639
+ propagate_sleepy (node , val , & set_sleepy , paravirt );
648
640
preempted = yield_head_to_locked_owner (lock , val , paravirt );
649
641
if (!maybe_stealers )
650
642
continue ;
0 commit comments