Deleted Added
full compact
subr_smp.c (222032) subr_smp.c (222254)
1/*-
2 * Copyright (c) 2001, John Baldwin <jhb@FreeBSD.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 19 unchanged lines hidden (view full) ---

28 */
29
30/*
31 * This module holds the global variables and machine independent functions
32 * used for the kernel SMP support.
33 */
34
35#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2001, John Baldwin <jhb@FreeBSD.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 19 unchanged lines hidden (view full) ---

28 */
29
30/*
31 * This module holds the global variables and machine independent functions
32 * used for the kernel SMP support.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/kern/subr_smp.c 222032 2011-05-17 16:39:08Z jhb $");
36__FBSDID("$FreeBSD: head/sys/kern/subr_smp.c 222254 2011-05-24 13:36:41Z jhb $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/ktr.h>
42#include <sys/proc.h>
43#include <sys/bus.h>
44#include <sys/lock.h>

--- 261 unchanged lines hidden (view full) ---

306 * resume.
307 *
308 * Note that the supplied external functions _must_ be reentrant and aware
309 * that they are running in parallel and in an unknown lock context.
310 */
311void
312smp_rendezvous_action(void)
313{
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/ktr.h>
42#include <sys/proc.h>
43#include <sys/bus.h>
44#include <sys/lock.h>

--- 261 unchanged lines hidden (view full) ---

306 * resume.
307 *
308 * Note that the supplied external functions _must_ be reentrant and aware
309 * that they are running in parallel and in an unknown lock context.
310 */
311void
312smp_rendezvous_action(void)
313{
314 struct thread *td;
314 void *local_func_arg;
315 void (*local_setup_func)(void*);
316 void (*local_action_func)(void*);
317 void (*local_teardown_func)(void*);
318 int generation;
315 void *local_func_arg;
316 void (*local_setup_func)(void*);
317 void (*local_action_func)(void*);
318 void (*local_teardown_func)(void*);
319 int generation;
320#ifdef INVARIANTS
321 int owepreempt;
322#endif
319
320 /* Ensure we have up-to-date values. */
321 atomic_add_acq_int(&smp_rv_waiters[0], 1);
322 while (smp_rv_waiters[0] < smp_rv_ncpus)
323 cpu_spinwait();
324
325 /* Fetch rendezvous parameters after acquire barrier. */
326 local_func_arg = smp_rv_func_arg;
327 local_setup_func = smp_rv_setup_func;
328 local_action_func = smp_rv_action_func;
329 local_teardown_func = smp_rv_teardown_func;
330 generation = smp_rv_generation;
331
332 /*
323
324 /* Ensure we have up-to-date values. */
325 atomic_add_acq_int(&smp_rv_waiters[0], 1);
326 while (smp_rv_waiters[0] < smp_rv_ncpus)
327 cpu_spinwait();
328
329 /* Fetch rendezvous parameters after acquire barrier. */
330 local_func_arg = smp_rv_func_arg;
331 local_setup_func = smp_rv_setup_func;
332 local_action_func = smp_rv_action_func;
333 local_teardown_func = smp_rv_teardown_func;
334 generation = smp_rv_generation;
335
336 /*
337 * Use a nested critical section to prevent any preemptions
338 * from occurring during a rendezvous action routine.
339 * Specifically, if a rendezvous handler is invoked via an IPI
340 * and the interrupted thread was in the critical_exit()
341 * function after setting td_critnest to 0 but before
342 * performing a deferred preemption, this routine can be
343 * invoked with td_critnest set to 0 and td_owepreempt true.
344 * In that case, a critical_exit() during the rendezvous
345 * action would trigger a preemption which is not permitted in
346 * a rendezvous action. To fix this, wrap all of the
347 * rendezvous action handlers in a critical section. We
348 * cannot use a regular critical section however as having
349 * critical_exit() preempt from this routine would also be
350 * problematic (the preemption must not occur before the IPI
351 * has been acknowleged via an EOI). Instead, we
352 * intentionally ignore td_owepreempt when leaving the
353 * critical setion. This should be harmless because we do not
354 * permit rendezvous action routines to schedule threads, and
355 * thus td_owepreempt should never transition from 0 to 1
356 * during this routine.
357 */
358 td = curthread;
359 td->td_critnest++;
360#ifdef INVARIANTS
361 owepreempt = td->td_owepreempt;
362#endif
363
364 /*
333 * If requested, run a setup function before the main action
334 * function. Ensure all CPUs have completed the setup
335 * function before moving on to the action function.
336 */
337 if (local_setup_func != smp_no_rendevous_barrier) {
338 if (smp_rv_setup_func != NULL)
339 smp_rv_setup_func(smp_rv_func_arg);
340 atomic_add_int(&smp_rv_waiters[1], 1);

--- 16 unchanged lines hidden (view full) ---

357 * rendezvous to be initiated on the same CPU or a different
358 * CPU. In that case the exit sentinel may be cleared before
359 * all CPUs have noticed causing those CPUs to hang forever.
360 * Workaround this by using a generation count to notice when
361 * this race occurs and to exit the rendezvous in that case.
362 */
363 MPASS(generation == smp_rv_generation);
364 atomic_add_int(&smp_rv_waiters[2], 1);
365 * If requested, run a setup function before the main action
366 * function. Ensure all CPUs have completed the setup
367 * function before moving on to the action function.
368 */
369 if (local_setup_func != smp_no_rendevous_barrier) {
370 if (smp_rv_setup_func != NULL)
371 smp_rv_setup_func(smp_rv_func_arg);
372 atomic_add_int(&smp_rv_waiters[1], 1);

--- 16 unchanged lines hidden (view full) ---

389 * rendezvous to be initiated on the same CPU or a different
390 * CPU. In that case the exit sentinel may be cleared before
391 * all CPUs have noticed causing those CPUs to hang forever.
392 * Workaround this by using a generation count to notice when
393 * this race occurs and to exit the rendezvous in that case.
394 */
395 MPASS(generation == smp_rv_generation);
396 atomic_add_int(&smp_rv_waiters[2], 1);
365 if (local_teardown_func == smp_no_rendevous_barrier)
366 return;
367 while (smp_rv_waiters[2] < smp_rv_ncpus &&
368 generation == smp_rv_generation)
369 cpu_spinwait();
397 if (local_teardown_func != smp_no_rendevous_barrier) {
398 while (smp_rv_waiters[2] < smp_rv_ncpus &&
399 generation == smp_rv_generation)
400 cpu_spinwait();
370
401
371 if (local_teardown_func != NULL)
372 local_teardown_func(local_func_arg);
402 if (local_teardown_func != NULL)
403 local_teardown_func(local_func_arg);
404 }
405
406 td->td_critnest--;
407 KASSERT(owepreempt == td->td_owepreempt,
408 ("rendezvous action changed td_owepreempt"));
373}
374
375void
376smp_rendezvous_cpus(cpumask_t map,
377 void (* setup_func)(void *),
378 void (* action_func)(void *),
379 void (* teardown_func)(void *),
380 void *arg)

--- 293 unchanged lines hidden ---
409}
410
411void
412smp_rendezvous_cpus(cpumask_t map,
413 void (* setup_func)(void *),
414 void (* action_func)(void *),
415 void (* teardown_func)(void *),
416 void *arg)

--- 293 unchanged lines hidden ---