|
37 | 37 | from drgn import StackFrame |
38 | 38 | from drgn.helpers.common import identify_address |
39 | 39 | from drgn.helpers.linux.cpumask import for_each_present_cpu |
| 40 | +from drgn.helpers.linux.list import list_empty |
40 | 41 | from drgn.helpers.linux.percpu import per_cpu |
41 | 42 | from drgn.helpers.linux.pid import find_task |
42 | 43 |
|
|
46 | 47 | from drgn_tools.deadlock import DependencyGraph |
47 | 48 | from drgn_tools.locking import _RWSEM_READER_MASK |
48 | 49 | from drgn_tools.locking import _RWSEM_READER_SHIFT |
| 50 | +from drgn_tools.locking import completion_for_each_task |
49 | 51 | from drgn_tools.locking import for_each_mutex_waiter |
50 | 52 | from drgn_tools.locking import for_each_rwsem_waiter |
51 | 53 | from drgn_tools.locking import get_lock_from_frame |
@@ -384,6 +386,61 @@ def show_rwsem_lock( |
384 | 386 | print("") |
385 | 387 |
|
386 | 388 |
|
| 389 | +def show_completion( |
| 390 | + prog: Program, |
| 391 | + frame_list: List[Tuple[Object, StackFrame]], |
| 392 | + stack: bool, |
| 393 | + time: Optional[int] = None, |
| 394 | + pid: Optional[int] = None, |
| 395 | +) -> None: |
| 396 | + """Show completion details""" |
| 397 | + wtask = None |
| 398 | + if pid is not None: |
| 399 | + wtask = find_task(prog, pid) |
| 400 | + |
| 401 | + seen_completions: Set[int] = set() |
| 402 | + completion_waiters: Set[int] = set() |
| 403 | + completions_done = 0 |
| 404 | + |
| 405 | + for task, frame in frame_list: |
| 406 | + completion = get_lock_from_frame(prog, task, frame, "completion", "x") |
| 407 | + if not completion: |
| 408 | + continue |
| 409 | + completion_addr = completion.value_() |
| 410 | + if completion_addr in seen_completions: |
| 411 | + continue |
| 412 | + seen_completions.add(completion_addr) |
| 413 | + |
| 414 | + index = 0 |
| 415 | + addr_info = _addr_info(prog, completion_addr) |
| 416 | + print(f"Completion: 0x{completion_addr:x}{addr_info}") |
| 417 | + if list_empty(completion.wait.task_list.address_of_()): |
| 418 | + completions_done = completions_done + 1 |
| 419 | + continue |
| 420 | + |
| 421 | + if pid is None: |
| 422 | + if time is None: |
| 423 | + time = 0 |
| 424 | + for waiter in completion_for_each_task(completion): |
| 425 | + completion_waiters.add(waiter.value_()) |
| 426 | + waittime = task_lastrun2now(waiter) |
| 427 | + timens = time * 1000000000 |
| 428 | + index = index + 1 |
| 429 | + if waittime > timens or timens == 0: |
| 430 | + show_lock_waiter(prog, waiter, index, stacktrace=stack) |
| 431 | + else: |
| 432 | + continue |
| 433 | + else: |
| 434 | + show_lock_waiter(prog, wtask, index, stacktrace=stack) |
| 435 | + |
| 436 | + print("") |
| 437 | + |
| 438 | + print(f"Number of tasks waiting on completions: {len(completion_waiters)}") |
| 439 | + print(f"Number of completions: {len(seen_completions)}") |
| 440 | + print(f"Number of completions wih no waiters: {completions_done}") |
| 441 | + print("") |
| 442 | + |
| 443 | + |
387 | 444 | def scan_sem_lock( |
388 | 445 | prog: Program, |
389 | 446 | stack: bool, |
@@ -433,6 +490,25 @@ def scan_rwsem_lock( |
433 | 490 | show_rwsem_lock(prog, frame_list, stack, time, pid) |
434 | 491 |
|
435 | 492 |
|
| 493 | +def scan_completion( |
| 494 | + prog: Program, |
| 495 | + stack: bool, |
| 496 | + time: Optional[int] = None, |
| 497 | + pid: Optional[int] = None, |
| 498 | +) -> None: |
| 499 | + """Scan for completion variables and show details""" |
| 500 | + wtask = None |
| 501 | + if pid is not None: |
| 502 | + wtask = find_task(prog, pid) |
| 503 | + |
| 504 | + functions = [ |
| 505 | + "__wait_for_common", |
| 506 | + ] |
| 507 | + frame_list = bt_has_any(prog, functions, wtask, one_per_task=True) |
| 508 | + if frame_list: |
| 509 | + show_completion(prog, frame_list, stack, time, pid) |
| 510 | + |
| 511 | + |
436 | 512 | def scan_lock( |
437 | 513 | prog: Program, |
438 | 514 | stack: bool, |
|
0 commit comments