| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: scheduler.c,v 1.28 2012/06/22 12:45:43 rmind Exp $ */ | | 1 | /* $NetBSD: scheduler.c,v 1.29 2012/09/15 17:15:01 pooka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. | | 4 | * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * | | 14 | * |
| @@ -16,27 +16,27 @@ | | | @@ -16,27 +16,27 @@ |
16 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | 16 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | * SUCH DAMAGE. | | 25 | * SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | #include <sys/cdefs.h> | | 28 | #include <sys/cdefs.h> |
29 | __KERNEL_RCSID(0, "$NetBSD: scheduler.c,v 1.28 2012/06/22 12:45:43 rmind Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: scheduler.c,v 1.29 2012/09/15 17:15:01 pooka Exp $"); |
30 | | | 30 | |
31 | #include <sys/param.h> | | 31 | #include <sys/param.h> |
32 | #include <sys/atomic.h> | | 32 | #include <sys/atomic.h> |
33 | #include <sys/cpu.h> | | 33 | #include <sys/cpu.h> |
34 | #include <sys/kmem.h> | | 34 | #include <sys/kmem.h> |
35 | #include <sys/mutex.h> | | 35 | #include <sys/mutex.h> |
36 | #include <sys/namei.h> | | 36 | #include <sys/namei.h> |
37 | #include <sys/queue.h> | | 37 | #include <sys/queue.h> |
38 | #include <sys/select.h> | | 38 | #include <sys/select.h> |
39 | #include <sys/systm.h> | | 39 | #include <sys/systm.h> |
40 | | | 40 | |
41 | #include <rump/rumpuser.h> | | 41 | #include <rump/rumpuser.h> |
42 | | | 42 | |
| @@ -290,44 +290,44 @@ rump_schedule_cpu_interlock(struct lwp * | | | @@ -290,44 +290,44 @@ rump_schedule_cpu_interlock(struct lwp * |
290 | /* | | 290 | /* |
291 | * First, try fastpath: if we were the previous user of the | | 291 | * First, try fastpath: if we were the previous user of the |
292 | * CPU, everything is in order cachewise and we can just | | 292 | * CPU, everything is in order cachewise and we can just |
293 | * proceed to use it. | | 293 | * proceed to use it. |
294 | * | | 294 | * |
295 | * If we are a different thread (i.e. CAS fails), we must go | | 295 | * If we are a different thread (i.e. CAS fails), we must go |
296 | * through a memory barrier to ensure we get a truthful | | 296 | * through a memory barrier to ensure we get a truthful |
297 | * view of the world. | | 297 | * view of the world. |
298 | */ | | 298 | */ |
299 | | | 299 | |
300 | KASSERT(l->l_target_cpu != NULL); | | 300 | KASSERT(l->l_target_cpu != NULL); |
301 | rcpu = &rcpu_storage[l->l_target_cpu-&rump_cpus[0]]; | | 301 | rcpu = &rcpu_storage[l->l_target_cpu-&rump_cpus[0]]; |
302 | if (atomic_cas_ptr(&rcpu->rcpu_prevlwp, l, RCPULWP_BUSY) == l) { | | 302 | if (atomic_cas_ptr(&rcpu->rcpu_prevlwp, l, RCPULWP_BUSY) == l) { |
303 | if (__predict_true(interlock == rcpu->rcpu_mtx)) | | 303 | if (interlock == rcpu->rcpu_mtx) |
304 | rumpuser_mutex_exit(rcpu->rcpu_mtx); | | 304 | rumpuser_mutex_exit(rcpu->rcpu_mtx); |
305 | SCHED_FASTPATH(rcpu); | | 305 | SCHED_FASTPATH(rcpu); |
306 | /* jones, you're the man */ | | 306 | /* jones, you're the man */ |
307 | goto fastlane; | | 307 | goto fastlane; |
308 | } | | 308 | } |
309 | | | 309 | |
310 | /* | | 310 | /* |
311 | * Else, it's the slowpath for us. First, determine if we | | 311 | * Else, it's the slowpath for us. First, determine if we |
312 | * can migrate. | | 312 | * can migrate. |
313 | */ | | 313 | */ |
314 | if (ncpu == 1) | | 314 | if (ncpu == 1) |
315 | domigrate = false; | | 315 | domigrate = false; |
316 | else | | 316 | else |
317 | domigrate = true; | | 317 | domigrate = true; |
318 | | | 318 | |
319 | /* Take lock. This acts as a load barrier too. */ | | 319 | /* Take lock. This acts as a load barrier too. */ |
320 | if (__predict_true(interlock != rcpu->rcpu_mtx)) | | 320 | if (interlock != rcpu->rcpu_mtx) |
321 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); | | 321 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); |
322 | | | 322 | |
323 | for (;;) { | | 323 | for (;;) { |
324 | SCHED_SLOWPATH(rcpu); | | 324 | SCHED_SLOWPATH(rcpu); |
325 | old = atomic_swap_ptr(&rcpu->rcpu_prevlwp, RCPULWP_WANTED); | | 325 | old = atomic_swap_ptr(&rcpu->rcpu_prevlwp, RCPULWP_WANTED); |
326 | | | 326 | |
327 | /* CPU is free? */ | | 327 | /* CPU is free? */ |
328 | if (old != RCPULWP_BUSY && old != RCPULWP_WANTED) { | | 328 | if (old != RCPULWP_BUSY && old != RCPULWP_WANTED) { |
329 | if (atomic_cas_ptr(&rcpu->rcpu_prevlwp, | | 329 | if (atomic_cas_ptr(&rcpu->rcpu_prevlwp, |
330 | RCPULWP_WANTED, RCPULWP_BUSY) == RCPULWP_WANTED) { | | 330 | RCPULWP_WANTED, RCPULWP_BUSY) == RCPULWP_WANTED) { |
331 | break; | | 331 | break; |
332 | } | | 332 | } |
333 | } | | 333 | } |
| @@ -432,53 +432,59 @@ rump_unschedule_cpu1(struct lwp *l, void | | | @@ -432,53 +432,59 @@ rump_unschedule_cpu1(struct lwp *l, void |
432 | void *old; | | 432 | void *old; |
433 | | | 433 | |
434 | ci = l->l_cpu; | | 434 | ci = l->l_cpu; |
435 | ci->ci_curlwp = NULL; | | 435 | ci->ci_curlwp = NULL; |
436 | rcpu = &rcpu_storage[ci-&rump_cpus[0]]; | | 436 | rcpu = &rcpu_storage[ci-&rump_cpus[0]]; |
437 | | | 437 | |
438 | KASSERT(rcpu->rcpu_ci == ci); | | 438 | KASSERT(rcpu->rcpu_ci == ci); |
439 | | | 439 | |
440 | /* | | 440 | /* |
441 | * Make sure all stores are seen before the CPU release. This | | 441 | * Make sure all stores are seen before the CPU release. This |
442 | * is relevant only in the non-fastpath scheduling case, but | | 442 | * is relevant only in the non-fastpath scheduling case, but |
443 | * we don't know here if that's going to happen, so need to | | 443 | * we don't know here if that's going to happen, so need to |
444 | * expect the worst. | | 444 | * expect the worst. |
| | | 445 | * |
| | | 446 | * If the scheduler interlock was requested by the caller, we |
| | | 447 | * need to obtain it before we release the CPU. Otherwise, we risk a |
| | | 448 | * race condition where another thread is scheduled onto the |
| | | 449 | * rump kernel CPU before our current thread can |
| | | 450 | * grab the interlock. |
445 | */ | | 451 | */ |
446 | membar_exit(); | | 452 | if (interlock == rcpu->rcpu_mtx) |
| | | 453 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); |
| | | 454 | else |
| | | 455 | membar_exit(); |
447 | | | 456 | |
448 | /* Release the CPU. */ | | 457 | /* Release the CPU. */ |
449 | old = atomic_swap_ptr(&rcpu->rcpu_prevlwp, l); | | 458 | old = atomic_swap_ptr(&rcpu->rcpu_prevlwp, l); |
450 | | | 459 | |
451 | /* No waiters? No problems. We're outta here. */ | | 460 | /* No waiters? No problems. We're outta here. */ |
452 | if (old == RCPULWP_BUSY) { | | 461 | if (old == RCPULWP_BUSY) { |
453 | /* Was the scheduler interlock requested? */ | | | |
454 | if (__predict_false(interlock == rcpu->rcpu_mtx)) | | | |
455 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); | | | |
456 | return; | | 462 | return; |
457 | } | | 463 | } |
458 | | | 464 | |
459 | KASSERT(old == RCPULWP_WANTED); | | 465 | KASSERT(old == RCPULWP_WANTED); |
460 | | | 466 | |
461 | /* | | 467 | /* |
462 | * Ok, things weren't so snappy. | | 468 | * Ok, things weren't so snappy. |
463 | * | | 469 | * |
464 | * Snailpath: take lock and signal anyone waiting for this CPU. | | 470 | * Snailpath: take lock and signal anyone waiting for this CPU. |
465 | */ | | 471 | */ |
466 | | | 472 | |
467 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); | | 473 | if (interlock != rcpu->rcpu_mtx) |
| | | 474 | rumpuser_mutex_enter_nowrap(rcpu->rcpu_mtx); |
468 | if (rcpu->rcpu_wanted) | | 475 | if (rcpu->rcpu_wanted) |
469 | rumpuser_cv_broadcast(rcpu->rcpu_cv); | | 476 | rumpuser_cv_broadcast(rcpu->rcpu_cv); |
470 | | | 477 | if (interlock != rcpu->rcpu_mtx) |
471 | if (__predict_true(interlock != rcpu->rcpu_mtx)) | | | |
472 | rumpuser_mutex_exit(rcpu->rcpu_mtx); | | 478 | rumpuser_mutex_exit(rcpu->rcpu_mtx); |
473 | } | | 479 | } |
474 | | | 480 | |
475 | /* Give up and retake CPU (perhaps a different one) */ | | 481 | /* Give up and retake CPU (perhaps a different one) */ |
476 | void | | 482 | void |
477 | yield() | | 483 | yield() |
478 | { | | 484 | { |
479 | struct lwp *l = curlwp; | | 485 | struct lwp *l = curlwp; |
480 | int nlocks; | | 486 | int nlocks; |
481 | | | 487 | |
482 | KERNEL_UNLOCK_ALL(l, &nlocks); | | 488 | KERNEL_UNLOCK_ALL(l, &nlocks); |
483 | rump_unschedule_cpu(l); | | 489 | rump_unschedule_cpu(l); |
484 | rump_schedule_cpu(l); | | 490 | rump_schedule_cpu(l); |