| 334 | } |
| 335 | |
| 336 | static void |
| 337 | lock_prof_reset(void) |
| 338 | { |
| 339 | struct lock_prof_cpu *lpc; |
| 340 | int enabled, i, cpu; |
| 341 | |
| 342 | /* |
| 343 | * We not only race with acquiring and releasing locks but also |
| 344 | * thread exit. To be certain that threads exit without valid head |
| 345 | * pointers they must see resetting set before enabled is cleared. |
| 346 | * Otherwise a lock may not be removed from a per-thread list due |
| 347 | * to disabled being set but not wait for reset() to remove it below. |
| 348 | */ |
| 349 | atomic_store_rel_int(&lock_prof_resetting, 1); |
| 350 | enabled = lock_prof_enable; |
| 351 | lock_prof_enable = 0; |
| 352 | /* |
| 353 | * This both publishes lock_prof_enable as disabled and makes sure |
| 354 | * everyone else reads it if they are not far enough. We wait for the |
| 355 | * rest down below. |
| 356 | */ |
| 357 | cpus_fence_seq_cst(); |
| 358 | quiesce_all_critical(); |
| 359 | /* |
| 360 | * Some objects may have migrated between CPUs. Clear all links |
| 361 | * before we zero the structures. Some items may still be linked |
| 362 | * into per-thread lists as well. |
| 363 | */ |
| 364 | CPU_FOREACH(cpu) { |
| 365 | lpc = LP_CPU(cpu); |
| 366 | for (i = 0; i < LPROF_CACHE_SIZE; i++) { |
| 367 | LIST_REMOVE(&lpc->lpc_types[0].lpt_objs[i], lpo_link); |
| 368 | LIST_REMOVE(&lpc->lpc_types[1].lpt_objs[i], lpo_link); |
| 369 | } |
| 370 | } |
| 371 | CPU_FOREACH(cpu) { |
| 372 | lpc = LP_CPU(cpu); |
| 373 | bzero(lpc, sizeof(*lpc)); |
| 374 | lock_prof_init_type(&lpc->lpc_types[0]); |
| 375 | lock_prof_init_type(&lpc->lpc_types[1]); |
| 376 | } |
| 377 | /* |
| 378 | * Paired with the fence from cpus_fence_seq_cst() |
| 379 | */ |
| 380 | atomic_store_rel_int(&lock_prof_resetting, 0); |
| 381 | lock_prof_enable = enabled; |
| 382 | } |
| 383 | |
| 384 | static void |
| 385 | lock_prof_output(struct lock_prof *lp, struct sbuf *sb) |
no test coverage detected