diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-29 13:19:27 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-29 13:19:27 -0500 |
| commit | 076d84bbdb396360d16aaa108c55aa1e24ad47a3 (patch) | |
| tree | 7ea509f9d6160fafa9ed6bdadeae649e204a8337 /kernel | |
| parent | d40e705903397445c6861a0a56c23e5b2e8f9b9a (diff) | |
| parent | 7be2a03e3174cee3a3cdcdf17db357470f51caff (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched
* git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched:
softlockup: fix task state setting
rcu: add support for dynamic ticks and preempt rcu
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/rcupreempt.c | 224 | ||||
| -rw-r--r-- | kernel/softirq.c | 1 | ||||
| -rw-r--r-- | kernel/softlockup.c | 13 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 3 |
4 files changed, 231 insertions, 10 deletions
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 987cfb7ade89..c7c52096df48 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c | |||
| @@ -23,6 +23,10 @@ | |||
| 23 | * to Suparna Bhattacharya for pushing me completely away | 23 | * to Suparna Bhattacharya for pushing me completely away |
| 24 | * from atomic instructions on the read side. | 24 | * from atomic instructions on the read side. |
| 25 | * | 25 | * |
| 26 | * - Added handling of Dynamic Ticks | ||
| 27 | * Copyright 2007 - Paul E. Mckenney <paulmck@us.ibm.com> | ||
| 28 | * - Steven Rostedt <srostedt@redhat.com> | ||
| 29 | * | ||
| 26 | * Papers: http://www.rdrop.com/users/paulmck/RCU | 30 | * Papers: http://www.rdrop.com/users/paulmck/RCU |
| 27 | * | 31 | * |
| 28 | * Design Document: http://lwn.net/Articles/253651/ | 32 | * Design Document: http://lwn.net/Articles/253651/ |
| @@ -409,6 +413,212 @@ static void __rcu_advance_callbacks(struct rcu_data *rdp) | |||
| 409 | } | 413 | } |
| 410 | } | 414 | } |
| 411 | 415 | ||
| 416 | #ifdef CONFIG_NO_HZ | ||
| 417 | |||
| 418 | DEFINE_PER_CPU(long, dynticks_progress_counter) = 1; | ||
| 419 | static DEFINE_PER_CPU(long, rcu_dyntick_snapshot); | ||
| 420 | static DEFINE_PER_CPU(int, rcu_update_flag); | ||
| 421 | |||
| 422 | /** | ||
| 423 | * rcu_irq_enter - Called from Hard irq handlers and NMI/SMI. | ||
| 424 | * | ||
| 425 | * If the CPU was idle with dynamic ticks active, this updates the | ||
| 426 | * dynticks_progress_counter to let the RCU handling know that the | ||
| 427 | * CPU is active. | ||
| 428 | */ | ||
| 429 | void rcu_irq_enter(void) | ||
| 430 | { | ||
| 431 | int cpu = smp_processor_id(); | ||
| 432 | |||
| 433 | if (per_cpu(rcu_update_flag, cpu)) | ||
| 434 | per_cpu(rcu_update_flag, cpu)++; | ||
| 435 | |||
| 436 | /* | ||
| 437 | * Only update if we are coming from a stopped ticks mode | ||
| 438 | * (dynticks_progress_counter is even). | ||
| 439 | */ | ||
| 440 | if (!in_interrupt() && | ||
| 441 | (per_cpu(dynticks_progress_counter, cpu) & 0x1) == 0) { | ||
| 442 | /* | ||
| 443 | * The following might seem like we could have a race | ||
| 444 | * with NMI/SMIs. But this really isn't a problem. | ||
| 445 | * Here we do a read/modify/write, and the race happens | ||
| 446 | * when an NMI/SMI comes in after the read and before | ||
| 447 | * the write. But NMI/SMIs will increment this counter | ||
| 448 | * twice before returning, so the zero bit will not | ||
| 449 | * be corrupted by the NMI/SMI which is the most important | ||
| 450 | * part. | ||
| 451 | * | ||
| 452 | * The only thing is that we would bring back the counter | ||
| 453 | * to a postion that it was in during the NMI/SMI. | ||
| 454 | * But the zero bit would be set, so the rest of the | ||
| 455 | * counter would again be ignored. | ||
| 456 | * | ||
| 457 | * On return from the IRQ, the counter may have the zero | ||
| 458 | * bit be 0 and the counter the same as the return from | ||
| 459 | * the NMI/SMI. If the state machine was so unlucky to | ||
| 460 | * see that, it still doesn't matter, since all | ||
| 461 | * RCU read-side critical sections on this CPU would | ||
| 462 | * have already completed. | ||
| 463 | */ | ||
| 464 | per_cpu(dynticks_progress_counter, cpu)++; | ||
| 465 | /* | ||
| 466 | * The following memory barrier ensures that any | ||
| 467 | * rcu_read_lock() primitives in the irq handler | ||
| 468 | * are seen by other CPUs to follow the above | ||
| 469 | * increment to dynticks_progress_counter. This is | ||
| 470 | * required in order for other CPUs to correctly | ||
| 471 | * determine when it is safe to advance the RCU | ||
| 472 | * grace-period state machine. | ||
| 473 | */ | ||
| 474 | smp_mb(); /* see above block comment. */ | ||
| 475 | /* | ||
| 476 | * Since we can't determine the dynamic tick mode from | ||
| 477 | * the dynticks_progress_counter after this routine, | ||
| 478 | * we use a second flag to acknowledge that we came | ||
| 479 | * from an idle state with ticks stopped. | ||
| 480 | */ | ||
| 481 | per_cpu(rcu_update_flag, cpu)++; | ||
| 482 | /* | ||
| 483 | * If we take an NMI/SMI now, they will also increment | ||
| 484 | * the rcu_update_flag, and will not update the | ||
| 485 | * dynticks_progress_counter on exit. That is for | ||
| 486 | * this IRQ to do. | ||
| 487 | */ | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | /** | ||
| 492 | * rcu_irq_exit - Called from exiting Hard irq context. | ||
| 493 | * | ||
| 494 | * If the CPU was idle with dynamic ticks active, update the | ||
| 495 | * dynticks_progress_counter to put let the RCU handling be | ||
| 496 | * aware that the CPU is going back to idle with no ticks. | ||
| 497 | */ | ||
| 498 | void rcu_irq_exit(void) | ||
| 499 | { | ||
| 500 | int cpu = smp_processor_id(); | ||
| 501 | |||
| 502 | /* | ||
| 503 | * rcu_update_flag is set if we interrupted the CPU | ||
| 504 | * when it was idle with ticks stopped. | ||
| 505 | * Once this occurs, we keep track of interrupt nesting | ||
| 506 | * because a NMI/SMI could also come in, and we still | ||
| 507 | * only want the IRQ that started the increment of the | ||
| 508 | * dynticks_progress_counter to be the one that modifies | ||
| 509 | * it on exit. | ||
| 510 | */ | ||
| 511 | if (per_cpu(rcu_update_flag, cpu)) { | ||
| 512 | if (--per_cpu(rcu_update_flag, cpu)) | ||
| 513 | return; | ||
| 514 | |||
| 515 | /* This must match the interrupt nesting */ | ||
| 516 | WARN_ON(in_interrupt()); | ||
| 517 | |||
| 518 | /* | ||
| 519 | * If an NMI/SMI happens now we are still | ||
| 520 | * protected by the dynticks_progress_counter being odd. | ||
| 521 | */ | ||
| 522 | |||
| 523 | /* | ||
| 524 | * The following memory barrier ensures that any | ||
| 525 | * rcu_read_unlock() primitives in the irq handler | ||
| 526 | * are seen by other CPUs to preceed the following | ||
| 527 | * increment to dynticks_progress_counter. This | ||
| 528 | * is required in order for other CPUs to determine | ||
| 529 | * when it is safe to advance the RCU grace-period | ||
| 530 | * state machine. | ||
| 531 | */ | ||
| 532 | smp_mb(); /* see above block comment. */ | ||
| 533 | per_cpu(dynticks_progress_counter, cpu)++; | ||
| 534 | WARN_ON(per_cpu(dynticks_progress_counter, cpu) & 0x1); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | static void dyntick_save_progress_counter(int cpu) | ||
| 539 | { | ||
| 540 | per_cpu(rcu_dyntick_snapshot, cpu) = | ||
| 541 | per_cpu(dynticks_progress_counter, cpu); | ||
| 542 | } | ||
| 543 | |||
| 544 | static inline int | ||
| 545 | rcu_try_flip_waitack_needed(int cpu) | ||
| 546 | { | ||
| 547 | long curr; | ||
| 548 | long snap; | ||
| 549 | |||
| 550 | curr = per_cpu(dynticks_progress_counter, cpu); | ||
| 551 | snap = per_cpu(rcu_dyntick_snapshot, cpu); | ||
| 552 | smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ | ||
| 553 | |||
| 554 | /* | ||
| 555 | * If the CPU remained in dynticks mode for the entire time | ||
| 556 | * and didn't take any interrupts, NMIs, SMIs, or whatever, | ||
| 557 | * then it cannot be in the middle of an rcu_read_lock(), so | ||
| 558 | * the next rcu_read_lock() it executes must use the new value | ||
| 559 | * of the counter. So we can safely pretend that this CPU | ||
| 560 | * already acknowledged the counter. | ||
| 561 | */ | ||
| 562 | |||
| 563 | if ((curr == snap) && ((curr & 0x1) == 0)) | ||
| 564 | return 0; | ||
| 565 | |||
| 566 | /* | ||
| 567 | * If the CPU passed through or entered a dynticks idle phase with | ||
| 568 | * no active irq handlers, then, as above, we can safely pretend | ||
| 569 | * that this CPU already acknowledged the counter. | ||
| 570 | */ | ||
| 571 | |||
| 572 | if ((curr - snap) > 2 || (snap & 0x1) == 0) | ||
| 573 | return 0; | ||
| 574 | |||
| 575 | /* We need this CPU to explicitly acknowledge the counter flip. */ | ||
| 576 | |||
| 577 | return 1; | ||
| 578 | } | ||
| 579 | |||
| 580 | static inline int | ||
| 581 | rcu_try_flip_waitmb_needed(int cpu) | ||
| 582 | { | ||
| 583 | long curr; | ||
| 584 | long snap; | ||
| 585 | |||
| 586 | curr = per_cpu(dynticks_progress_counter, cpu); | ||
| 587 | snap = per_cpu(rcu_dyntick_snapshot, cpu); | ||
| 588 | smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ | ||
