def get_fiber_managers()

in folly/fibers/scripts/gdb.py [0:0]


def get_fiber_managers(only=None):
    """iterator of (mid, manager) tuples

    Can filter output with "M.*" or "M" format, e.g. "2.3" for manager 2 (fiber is
    ignored) or "1" for manager 1.
    """
    # first check if pre-cached
    if get_fiber_managers.cache:
        for (mid, manager) in get_fiber_managers.cache.items():
            # output only if matching filter
            if not only or str(mid) in only:
                yield (mid, manager)
        return

    # extract the unique managers from the fiber filters
    only = {i.partition(".")[0] for i in only or []}
    managers = collections.OrderedDict()
    mgr_map = None
    for evb_type in ("folly::EventBase", "folly::VirtualEventBase"):
        # this can possibly return an empty map, even if it exists
        try:
            mgr_map = get_fiber_manager_map(evb_type)
        except gdb.GdbError:
            continue
        # the map pretty printer knows how to extract map entries
        map_pp = gdb.default_visualizer(mgr_map)

        # The children are alternating pairs of (_, (evb, int))/(_, uptr<FiberManager>)
        # the first entry is irrelevant, just an internal name for the pretty printer
        mid = 0

        for _, entry in map_pp.children():
            # The "key" in this map is std::pair<EventBaseT, long>, and the long is
            # almost always 0 (used for frozen options).  We'll ignore it and just use
            # our own internal id.  We unwrap the unique_ptr, though.
            if "unique_ptr" not in entry.type.tag:
                mid += 1
                continue

            # we have a value, make sure we have a unique key
            assert mid not in managers
            value = gdb.default_visualizer(entry)

            # Before GCC9, the stl gdb libs don't expose the unique_ptr target
            # address except through the pretty printer, as the last
            # space-delimited word. From GCC9 forward, the unique_ptr visualizer
            # exposes a children iterator with the target address. We extract
            # that address whicever way we can, then create a new gdb.Value of
            # that address cast to the fibermanager type.
            address = None
            if callable(getattr(value, "children", None)):
                for _, pointer in value.children():
                    address = pointer
            else:
                address = int(value.to_string().split(" ")[-1], 16)

            if address is not None:
                manager = (
                    gdb.Value(address)
                    .cast(gdb.lookup_type("folly::fibers::FiberManager").pointer())
                    .dereference()
                )

                # output only if matching filter
                if not only or str(mid) in only:
                    yield (mid, manager)

        # set cache
        get_fiber_managers.cache = managers