]> git.proxmox.com Git - mirror_frr.git/commitdiff
*: Rename thread.[ch] to event.[ch]
authorDonald Sharp <sharpd@nvidia.com>
Mon, 28 Feb 2022 15:40:31 +0000 (10:40 -0500)
committerDonald Sharp <sharpd@nvidia.com>
Fri, 24 Mar 2023 12:32:16 +0000 (08:32 -0400)
This is a first in a series of commits, whose goal is to rename
the thread system in FRR to an event system.  There is a continual
problem where people are confusing `struct thread` with a true
pthread.  In reality, our entire thread.c is an event system.

In this commit rename the thread.[ch] files to event.[ch].

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
234 files changed:
babeld/babel_main.c
babeld/kernel.c
bfdd/dplane.c
bgpd/bgp_advertise.c
bgpd/bgp_bfd.c
bgpd/bgp_bmp.c
bgpd/bgp_damp.c
bgpd/bgp_dump.c
bgpd/bgp_fsm.c
bgpd/bgp_io.c
bgpd/bgp_label.c
bgpd/bgp_main.c
bgpd/bgp_mplsvpn_snmp.c
bgpd/bgp_network.c
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_rpki.c
bgpd/bgp_snmp.c
bgpd/bgp_snmp_bgp4.c
bgpd/bgp_snmp_bgp4v2.c
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_import.h
bgpd/rfapi/vnc_export_table.h
doc/developer/modules.rst
doc/developer/process-architecture.rst
eigrpd/eigrp_dump.c
eigrpd/eigrp_filter.c
eigrpd/eigrp_fsm.c
eigrpd/eigrp_hello.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_main.c
eigrpd/eigrp_neighbor.c
eigrpd/eigrp_network.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_query.c
eigrpd/eigrp_reply.c
eigrpd/eigrp_siaquery.c
eigrpd/eigrp_siareply.c
eigrpd/eigrp_snmp.c
eigrpd/eigrp_update.c
eigrpd/eigrp_vty.c
eigrpd/eigrp_zebra.c
eigrpd/eigrpd.c
gdb/lib.txt
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_csm.c
isisd/isis_dr.c
isisd/isis_dynhn.c
isisd/isis_events.c
isisd/isis_ldp_sync.c
isisd/isis_lsp.c
isisd/isis_main.c
isisd/isis_pdu.c
isisd/isis_route.c
isisd/isis_routemap.c
isisd/isis_spf.c
isisd/isis_te.c
isisd/isis_zebra.c
isisd/isisd.c
ldpd/ldpd.h
lib/bfd.c
lib/command.c
lib/event.c [new file with mode: 0644]
lib/event.h [new file with mode: 0644]
lib/frr_pthread.h
lib/frr_zmq.c
lib/frr_zmq.h
lib/ldp_sync.c
lib/libfrr.h
lib/libfrr_trace.h
lib/mgmt_fe_client.h
lib/mgmt_msg.c
lib/mgmt_msg.h
lib/northbound.h
lib/northbound_grpc.cpp
lib/pullwr.h
lib/qobj.c
lib/resolver.c
lib/resolver.h
lib/sigevent.h
lib/smux.h
lib/spf_backoff.c
lib/subdir.am
lib/systemd.c
lib/thread.c [deleted file]
lib/thread.h [deleted file]
lib/vty.c
lib/vty.h
lib/wheel.c
lib/workqueue.c
lib/zclient.c
lib/zlog.c
lib/zlog_5424.c
mgmtd/mgmt_be_adapter.c
mgmtd/mgmt_history.c
nhrpd/netlink_arp.c
nhrpd/nhrp_cache.c
nhrpd/nhrp_event.c
nhrpd/nhrp_interface.c
nhrpd/nhrp_main.c
nhrpd/nhrp_multicast.c
nhrpd/nhrp_nhs.c
nhrpd/nhrp_packet.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_shortcut.c
nhrpd/nhrp_vc.c
nhrpd/vici.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_bfd.c
ospf6d/ospf6_flood.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_main.c
ospf6d/ospf6_message.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_nssa.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_top.c
ospf6d/ospf6d.c
ospf6d/ospf6d.h
ospfclient/ospf_apiclient.c
ospfclient/ospfclient.c
ospfd/ospf_abr.c
ospfd/ospf_api.c
ospfd/ospf_apiserver.c
ospfd/ospf_asbr.c
ospfd/ospf_ase.c
ospfd/ospf_bfd.c
ospfd/ospf_dump.c
ospfd/ospf_ext.c
ospfd/ospf_flood.c
ospfd/ospf_gr_helper.c
ospfd/ospf_ia.c
ospfd/ospf_interface.c
ospfd/ospf_ism.c
ospfd/ospf_ldp_sync.c
ospfd/ospf_lsa.c
ospfd/ospf_main.c
ospfd/ospf_neighbor.c
ospfd/ospf_network.c
ospfd/ospf_nsm.c
ospfd/ospf_opaque.c
ospfd/ospf_packet.c
ospfd/ospf_ri.c
ospfd/ospf_spf.c
ospfd/ospf_sr.c
ospfd/ospf_te.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
pathd/path_main.c
pathd/path_pcep_config.c
pathd/path_zebra.c
pbrd/pbr_main.c
pbrd/pbr_map.c
pbrd/pbr_zebra.c
pimd/pim6_mld.c
pimd/pim_ifchannel.c
pimd/pim_main.c
pimd/pim_msdp.c
pimd/pim_msdp_packet.c
pimd/pim_msdp_socket.c
pimd/pim_pim.c
pimd/pim_register.c
pimd/pim_time.c
pimd/pim_time.h
pimd/pim_upstream.c
pimd/pim_zlookup.c
python/xref2vtysh.py
ripd/rip_interface.c
ripd/rip_main.c
ripd/rip_peer.c
ripd/ripd.c
ripngd/ripng_interface.c
ripngd/ripng_main.c
ripngd/ripng_peer.c
ripngd/ripngd.c
sharpd/sharp_logpump.c
sharpd/sharp_main.c
sharpd/sharp_zebra.c
staticd/static_main.c
staticd/static_zebra.c
tests/helpers/c/main.c
tests/isisd/test_fuzz_isis_tlv.c
tests/isisd/test_isis_spf.c
tests/lib/cli/common_cli.c
tests/lib/cxxcompat.c
tests/lib/northbound/test_oper_data.c
tests/lib/test_assert.c
tests/lib/test_grpc.cpp
tests/lib/test_heavy.c
tests/lib/test_heavy_thread.c
tests/lib/test_heavy_wq.c
tests/lib/test_stream.c
tests/lib/test_timer_correctness.c
tests/lib/test_timer_performance.c
tests/ospfd/test_ospf_spf.c
vrrpd/vrrp.h
vrrpd/vrrp_main.c
watchfrr/watchfrr.c
zebra/if_netlink.c
zebra/irdp_interface.c
zebra/irdp_main.c
zebra/irdp_packet.c
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/label_manager.h
zebra/main.c
zebra/rt_netlink.c
zebra/rtadv.c
zebra/table_manager.h
zebra/zebra_fpm.c
zebra/zebra_gr.c
zebra/zebra_mlag_private.c
zebra/zebra_mpls.c
zebra/zebra_netns_notify.c
zebra/zebra_pw.c
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zserv.c
zebra/zserv.h

index 0869c120ac827058c471c6c6d5446f18574692ed..de0c8230fc27b2958ac548176414b3faf2cfe7eb 100644 (file)
@@ -8,7 +8,7 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
 #include "getopt.h"
 #include "if.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "sigevent.h"
 #include "lib/version.h"
index f89fe268df370d362fbab054fda02eddc544666f..bbbb9676eb22e1a7f90d97bc3f92ddee86a6d29a 100644 (file)
@@ -29,7 +29,7 @@ Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek
 #include "command.h"
 #include "vty.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "nexthop.h"
 
 #include "util.h"
index 99bd1886f48c13845c660fe7734a3568f7e991c4..7d160e868a9da510eb301ff2855212bcad0b07ec 100644 (file)
@@ -26,7 +26,7 @@
 #include "lib/network.h"
 #include "lib/printfrr.h"
 #include "lib/stream.h"
-#include "lib/thread.h"
+#include "lib/event.h"
 
 #include "bfd.h"
 #include "bfddp_packet.h"
index 3469d129e4c5c09633b36d654bd893f992f9ff2c..429abc17907a5bbbb94fb31724c0a42434f949b3 100644 (file)
@@ -9,7 +9,7 @@
 #include "memory.h"
 #include "prefix.h"
 #include "hash.h"
-#include "thread.h"
+#include "event.h"
 #include "queue.h"
 #include "filter.h"
 
index 4a81b69ced305756f4abc8da3d13dce9c0f533ed..bdbaf6226725f8e6a838671b95625ef99e00e001 100644 (file)
@@ -11,7 +11,7 @@
 #include "linklist.h"
 #include "memory.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "vrf.h"
index 40a27cad70f1a3fb5115b61edcf61da8602c4814..6ade0fc38890269405d65f5d986fcce063364516 100644 (file)
@@ -11,7 +11,7 @@
 #include "sockunion.h"
 #include "command.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "queue.h"
 #include "pullwr.h"
index 54bbf9b9ca9d09bebea000d3e97521394b3c31ae..ba16a33fb9a6937c17553c8bf208cda9a558325c 100644 (file)
@@ -10,7 +10,7 @@
 #include "memory.h"
 #include "command.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "queue.h"
 #include "filter.h"
 
index 794dd7b8b65c5a2a8f453844e2aef093a3e5d8fe..6aad4ff2a7cbb2c598feb8cdf7239d7430c069c3 100644 (file)
@@ -10,7 +10,7 @@
 #include "sockunion.h"
 #include "command.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "queue.h"
 #include "memory.h"
index aa9a6a8602cb73736a63d77ec17be12875257fa2..dc6ce6b8eb926b1d5e59b8d0400b46d2c71c834f 100644 (file)
@@ -9,7 +9,7 @@
 #include "linklist.h"
 #include "prefix.h"
 #include "sockunion.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "stream.h"
 #include "ringbuf.h"
index 530b77987d0c07cd96593f4d720e938caaf28c78..5dae39d40caa9eb68576489cc0f48a3f8d01be01 100644 (file)
@@ -17,7 +17,7 @@
 #include "network.h"           // for ERRNO_IO_RETRY
 #include "stream.h"            // for stream_get_endp, stream_getw_from, str...
 #include "ringbuf.h"           // for ringbuf_remain, ringbuf_peek, ringbuf_...
-#include "thread.h"            // for THREAD_OFF, THREAD_ARG, thread...
+#include "event.h"             // for THREAD_OFF, THREAD_ARG, thread...
 
 #include "bgpd/bgp_io.h"
 #include "bgpd/bgp_debug.h"    // for bgp_debug_neighbor_events, bgp_type_str
index 414dafebd4e5eae0965ed8aaaa105dbda9459781..c13e0b0daf2e41c5819b07734d7dcadd500ac82f 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "zclient.h"
 #include "stream.h"
index 85e49043725e04e98426b9282cb0b6557cc94277..63dab9070a24cf27d3b490f1334470e8d6c36a28 100644 (file)
@@ -9,7 +9,7 @@
 #include "vector.h"
 #include "command.h"
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include <lib/version.h>
 #include "memory.h"
 #include "prefix.h"
index 8453133dfff9cc6d4934d1eece38ef0fc3202bd1..52320031c7bbe63b32bb9cdd72b401b3f88792c6 100644 (file)
@@ -12,7 +12,7 @@
 #include "log.h"
 #include "prefix.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "smux.h"
 #include "filter.h"
 #include "hook.h"
index 6f035358f1c6e9c1a48de07f507e9dc33997a06d..8fcb5b017e3a80eeee830fdfd0480d3fffba029d 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "sockunion.h"
 #include "sockopt.h"
 #include "memory.h"
index f1f6b031a98a25ef2db27c11189ebb89f2e9ca44..2ccc5e2c335360596bfeaf32656cb2bf0b6fbd46 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "lib/json.h"
 #include "zclient.h"
index 473c95071c3423eaa80a45db86ec6e0d12e6de66..cb9de84cc58812ee73749eac8c04254f6efd5b95 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "zclient.h"
 #include "stream.h"
index 032767820f5c864212e844dcffe33bc5169fa78c..457f7be7eb85d0f95623e4618cf8b11aa2cd24a2 100644 (file)
@@ -8,7 +8,7 @@
 #include "linklist.h"
 #include "prefix.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "command.h"
 #include "memory.h"
index 93672d29f13dea6c6bfb18887614c651ba90d77b..97b26ea62a27c8e6c6d1b7788bd11dc5f4bc40a8 100644 (file)
@@ -8,7 +8,7 @@
 #include <zebra.h>
 #include <sys/time.h>
 
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "network.h"
 #include "prefix.h"
index 14ce4e6bc9ba74e6f7a9e9d853c945a2c4c733dc..efa367a56d3b833eb5de377510b0556c313ce3c7 100644 (file)
@@ -20,7 +20,7 @@
 #include "buffer.h"
 #include "sockunion.h"
 #include "plist.h"
-#include "thread.h"
+#include "event.h"
 #include "workqueue.h"
 #include "queue.h"
 #include "memory.h"
index 32ca909fe6145149d667331a85381f5075fd84d4..2aceca8bd7108db4122c38d49fe814457c6098e7 100644 (file)
@@ -23,7 +23,7 @@
 #include "command.h"
 #include "linklist.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "filter.h"
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
@@ -36,7 +36,6 @@
 #include "northbound_cli.h"
 
 #include "lib/network.h"
-#include "lib/thread.h"
 #include "rtrlib/rtrlib.h"
 #include "hook.h"
 #include "libfrr.h"
index 5aa5e142889cdc3c36bd8f82c0ba8c876cd99df5..7408b77656cb8acdceaa66d7fc23bc167e63e83a 100644 (file)
@@ -12,7 +12,7 @@
 #include "log.h"
 #include "prefix.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "smux.h"
 #include "filter.h"
 #include "hook.h"
index 186c9e28463aac39d61f29ef24a1bc807f4a4b7d..3bf3c61bf32be31ffdbcea22e59d0e836b1f2264 100644 (file)
@@ -12,7 +12,7 @@
 #include "log.h"
 #include "prefix.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "smux.h"
 #include "filter.h"
 #include "hook.h"
index 9c2599d5f4706be451c97b685403df53b4412bed..61615be2c5818369715260edc1d9aafeb1c48159 100644 (file)
@@ -13,7 +13,7 @@
 #include "log.h"
 #include "prefix.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "smux.h"
 #include "filter.h"
 #include "hook.h"
index 204b8092e5545efc01ed054f1e9d49535ea8573a..68bfb4c13987d442e70bebb9b112653ac4b61133 100644 (file)
@@ -12,7 +12,7 @@
 #include <zebra.h>
 
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "command.h"
index d8e0e7875cef4fc44bf4bcfe134df069f1cdf0ea..181d57813d22f56edb65d341dec1b0ed5b13c540 100644 (file)
@@ -17,7 +17,7 @@
 #include "memory.h"
 #include "prefix.h"
 #include "hash.h"
-#include "thread.h"
+#include "event.h"
 #include "queue.h"
 #include "routemap.h"
 #include "filter.h"
index 5106dcf354cc4068a707756cad5bd809e895f09a..279a7cce6076199da4d5032c29723eabbd9744b3 100644 (file)
@@ -12,7 +12,7 @@
 #include <zebra.h>
 
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "command.h"
index 93b412240aadc8275af29c5503f87dd9eb931a27..3bc64c34991486945d164f22059729057357ada7 100644 (file)
@@ -16,7 +16,7 @@
 #include "buffer.h"
 #include "linklist.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "memory.h"
 #include "lib_vty.h"
index da598993d145480e4520bf5e4da041af82e01dcc..d4c98a2c73072c62022f4ccc689a96cf28893cad 100644 (file)
@@ -13,7 +13,7 @@
 #include "sockunion.h"
 #include "zclient.h"
 #include "routemap.h"
-#include "thread.h"
+#include "event.h"
 #include "queue.h"
 #include "memory.h"
 #include "lib/json.h"
index 96c6a111ce3b3e1cf30421c08acc639900f83510..c7cd80b98438407ac9bb248abef9e83eec198b80 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "ringbuf.h"
index 25a4403040207f24335d8000e19c33ce08142822..5fb2c5046df95a597474a4d9c6d397c7930b3a6a 100644 (file)
@@ -15,7 +15,7 @@
 #include "lib/memory.h"
 #include "lib/log.h"
 #include "lib/skiplist.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/stream.h"
 #include "lib/lib_errors.h"
 
index 3bec225f65ace0d61e139ab39fd90629bd983b86..7e021e8f7a8a521c06a06cfbb5349652ed6c5257 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef QUAGGA_HGP_RFAPI_IMPORT_H
 #define QUAGGA_HGP_RFAPI_IMPORT_H
 
-#include "lib/thread.h"
+#include "event.h"
 
 /*
  * These are per-rt-import-list
index 42c04f0c79564847074fef8381a96ccf4bda2964..5716570cb00fdd1266e562e2aad71fec724f013b 100644 (file)
@@ -9,7 +9,7 @@
 #define _QUAGGA_VNC_VNC_EXPORT_TABLE_H_
 
 #include "lib/table.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/vty.h"
 
 #include "bgpd/bgpd.h"
index e95f8a1b4a72eebd2f63c95b30f5e801056bd2bd..89d2f81f1b4cd92cbeb23047c5c16afac969820a 100644 (file)
@@ -56,7 +56,7 @@ Basic boilerplate:
     #include "hook.h"
     #include "module.h"
     #include "libfrr.h"
-    #include "thread.h"
+    #include "event.h"
 
     static int module_late_init(struct thread_master *master)
     {
index 37bd620f24638abce1cfc040f8869cfe6cfc0b67..4f6cfcc7c59adbc177b496a3825f7f7ca446f599 100644 (file)
@@ -57,7 +57,7 @@ execute. At initialization, a daemon will typically create one
 fetch each task and execute it.
 
 These tasks have various types corresponding to their general action. The types
-are given by integer macros in :file:`thread.h` and are:
+are given by integer macros in :file:`event.h` and are:
 
 ``THREAD_READ``
    Task which waits for a file descriptor to become ready for reading and then
@@ -144,7 +144,7 @@ macros wrap underlying functions in :file:`thread.c` to provide additional
 information added at compile time, such as the line number the task was
 scheduled from, that can be accessed at runtime for debugging, logging and
 informational purposes. Each task type has its own specific scheduling function
-that follow the naming convention ``thread_add_<type>``; see :file:`thread.h`
+that follow the naming convention ``thread_add_<type>``; see :file:`event.h`
 for details.
 
 There are some gotchas to keep in mind:
index 489b3bd1c537bfc2bf3fcb2786db9fe364e05833..b7c7e0070dbe0dd9238b9c89d66c5c2960a4aa9b 100644 (file)
@@ -13,7 +13,7 @@
 #include <zebra.h>
 
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "command.h"
 #include "stream.h"
index 09ae6be6dc7d83b42475bb335621fab35e45fff1..534b4fef56491ae46733926ea9168bfae1004ebc 100644 (file)
@@ -21,7 +21,7 @@
 #include "command.h"
 #include "prefix.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "log.h"
 #include "stream.h"
index d065af0cb91998fc9ed18c0b41cb171e1ddf9721..cdfc99fce0e23919f857da6ae861ae2c632583a3 100644 (file)
@@ -53,8 +53,8 @@
  */
 
 #include <zebra.h>
-#include <thread.h>
 
+#include "event.h"
 #include "prefix.h"
 #include "table.h"
 #include "memory.h"
index f62f54b680671f7e65bc9f8e900d6097a241b4e1..55f0a3269ffb930aa619673cbeb3aab9cc578b7e 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 8d98dcf5a18f5d851fbaaed3db5c5d228c2513f1..eeb2bd4d09c0b24377a36a71806170b93f77dd51 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "if.h"
index 3c1e5da3400427a63564f59f9f220ad5e2902aef..5cd1353a9f18175595fe414f3dd6de5f474d4425 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "linklist.h"
 #include "if.h"
index 9288b0f1cd7c80bd9bb2afdb8a12124587f907c0..f427067b3653beec4a83758e73784879a724be07 100644 (file)
@@ -20,7 +20,7 @@
 #include "prefix.h"
 #include "memory.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "table.h"
 #include "log.h"
index 68edd0898a3a0cb73f41d47a4b07be6c167aa78a..4e5580480b3526dea6d53b1553afbc937997e48e 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "if.h"
index e00d62fb0869fe3b27c68732789577d905bdfb5c..02fb3d23b84aed5f652a0f0b706eb5900037c74c 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "vty.h"
index 56498ed674793ffe65f9a20efb6270decfb9ef9a..7e21eb79a0415ecb6561b9a6bc8eb83a57d51e21 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index a1413fe9c71285ec6949d32b4be434927a8049a8..07d1fd75d6b655dc8735b8e2e19ed37429102542 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 1c2ec3731f8c1bc1ac12317534e7468f64080337..f4ddf1da32312785b1c29cdf620338111b3a408c 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 37cca67373e2da43ffcbb1639ec3e1642b0384ae..aaea1df778b48a52d3d37131c45f2530ec1fe4ee 100644 (file)
@@ -11,7 +11,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index f159415ccb8994c4a1cce74853856a73598adab2..efa72e3a099a8bbfa8a623a511fd685f144e9552 100644 (file)
@@ -16,7 +16,7 @@
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 49acf3069566f535c210de528d5b1ac9cce495fd..6d4b3eb8e9f7972eebb9f0a0bc4560ba63fa3928 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 33f728ec4b923a71378b0014bb4f8018e9b47c93..c4dba8bc31f53cc81281da51bdf3f7599155909d 100644 (file)
@@ -17,7 +17,7 @@
 #include <zebra.h>
 
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "table.h"
 #include "vty.h"
index 179c2d0f2aa88bdc9e58c4464e8c1610a6692081..0ae8c3b45ed8eb6f424ed0e53af9c5ac57d79955 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "network.h"
 #include "prefix.h"
index a382862e3dc53bae2dd954b6fc3afb8e0d708e4d..9db0531b59a71161d4cec3b5c8bd8c28d1e798a3 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "linklist.h"
index b44c2379855825e693b0b35f2fba1211cfdc6da4..5d22321b6291bf2c730fced71a98011b5fbc020c 100644 (file)
@@ -157,7 +157,7 @@ document walk_route_table
 Walk through a routing table (or subset thereof) and dump all the non-null
 (struct route_node *)->info pointers.
 
-Argument: A lib/thread.h::(struct route_node *) pointing to the route_node
+Argument: A lib/hread.h::(struct route_node *) pointing to the route_node
 under which all data should be dumped
 end
 
index cb2cf8f61190344397d8f5c1ba6e4b0d0e05ff36..16def982b791d3c4fe8b1a047a7a54fed8454804 100644 (file)
@@ -15,7 +15,7 @@
 #include "hash.h"
 #include "vty.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "if.h"
 #include "stream.h"
 #include "bfd.h"
index 1ee7f4451dc18bb2b10437d45df1d1642647ef1b..8593aee8be567da1e7bc161efb810fe6226b8603 100644 (file)
@@ -19,7 +19,7 @@
 #include "if.h"
 #include "linklist.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "hash.h"
 #include "prefix.h"
index 95bbc077a32c8170b53d2a5c8ff144c6931ff6f5..2b460e10cfbb456519263851eaf6e3915f3c191d 100644 (file)
@@ -14,7 +14,7 @@
 #include "if.h"
 #include "linklist.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "prefix.h"
 #include "stream.h"
index b1a42158130b350581389d927b73bed7ab56a594..5b236a66d7d3a35c7828d5a2cd36094b034b5a92 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "log.h"
 #include "hash.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "stream.h"
index ef21de327eb6aaed359c822e4097cf581206132e..667a90c2cfe51233864e7869b705462a7aeabe3f 100644 (file)
@@ -16,7 +16,7 @@
 #include "stream.h"
 #include "command.h"
 #include "if.h"
-#include "thread.h"
+#include "event.h"
 
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
index d7b3969114084e1999a204d863e5aa6260e71c5b..87b6061b5882599ffd1c1f6974055a37bde3edf4 100644 (file)
@@ -13,7 +13,7 @@
 #include "if.h"
 #include "linklist.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "prefix.h"
 #include "stream.h"
index 817e2a2015213e9893463a2229f2d7d2f6a99a75..497906aaeca7a9668cb81c59679ce13bb1e1e7ae 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "monotime.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "table.h"
 #include "vty.h"
index 4a332d0aed8efee9a7195d726e634fa9e9074b67..59cedec706c0dc33bfd17f08f9f525f05899119b 100644 (file)
@@ -12,7 +12,7 @@
 #include <zebra.h>
 
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "stream.h"
 #include "memory.h"
index 25ea187492eaf8d4a7d90d04c16ba47ec41af39f..99a18fc31c8930ead02d87246fad6e2f2ff66e8e 100644 (file)
@@ -10,7 +10,7 @@
 #include <zebra.h>
 
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include <lib/version.h>
 #include "command.h"
index f659f3abc346f7540675b5d689de02470c1c6232..ec1b8d2686ef3ea0fda12560517f93425a7823e5 100644 (file)
@@ -11,7 +11,7 @@
 #include <zebra.h>
 
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "log.h"
 #include "stream.h"
index 711d5cbed9f481e03149579aaf7077e30ac2c84a..57f59721239ee7934943b40cb41d7872381e28fb 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "log.h"
index 632b4ff95ec7835705c68145d9e0d0b65c409d65..6d2a1f1599cefc0e115c0e8394788578c2d7ca06 100644 (file)
@@ -18,7 +18,7 @@
 #include "plist.h"
 #include "routemap.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 
 #include "isis_constants.h"
index 9229f0a77d62062b0e093181afa79257e8a3b2cf..90f5ff69a2cea7374133c4b8399cbd7cbfd8c236 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "log.h"
index 3659f4e07c676f77a0b80761a3f123d3c31fce05..9d859c222be859ca46b39586350a1996af8e28f5 100644 (file)
@@ -13,7 +13,7 @@
 #include <math.h>
 
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "stream.h"
 #include "memory.h"
index 7e85576c7a3d658da5c7311bc0775a12d5db5421..c344f16347162f180525f44de406b57fe8f572e3 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "memory.h"
 #include "log.h"
index 586785b05f21908001fb1b8a5b69f7d7d000e877..ee402dad93e464e75beb9f3c774ad773038a139a 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "log.h"
index dc993e3d7cc645571873c9e3c1b9f143adbc791f..cbf91655388bd5a2011627c9674c99703a137d84 100644 (file)
@@ -14,7 +14,7 @@
 #include "queue.h"
 #include "openbsd-tree.h"
 #include "imsg.h"
-#include "thread.h"
+#include "event.h"
 #include "qobj.h"
 #include "prefix.h"
 #include "filter.h"
index c1e0fff7f578ed58ef95b1e934f5377dd6a66350..c430b1d7efd982aea9b3ce8145d0b724846d3b8d 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -10,7 +10,7 @@
 #include "command.h"
 #include "memory.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "vrf.h"
 #include "zclient.h"
index 196d73d46a4bde5316b333b4af5435dc6442d143..e2de6f322bd810280d70c2b2f9d10b535c5f3a64 100644 (file)
@@ -17,7 +17,7 @@
 #include "memory.h"
 #include "log.h"
 #include "log_vty.h"
-#include "thread.h"
+#include "event.h"
 #include "vector.h"
 #include "linklist.h"
 #include "vty.h"
diff --git a/lib/event.c b/lib/event.c
new file mode 100644 (file)
index 0000000..b0f901a
--- /dev/null
@@ -0,0 +1,2198 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Thread management routine
+ * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ */
+
+/* #define DEBUG */
+
+#include <zebra.h>
+#include <sys/resource.h>
+
+#include "event.h"
+#include "memory.h"
+#include "frrcu.h"
+#include "log.h"
+#include "hash.h"
+#include "command.h"
+#include "sigevent.h"
+#include "network.h"
+#include "jhash.h"
+#include "frratomic.h"
+#include "frr_pthread.h"
+#include "lib_errors.h"
+#include "libfrr_trace.h"
+#include "libfrr.h"
+
+DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread");
+DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master");
+DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info");
+DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats");
+
+DECLARE_LIST(thread_list, struct thread, threaditem);
+
+struct cancel_req {
+       int flags;
+       struct thread *thread;
+       void *eventobj;
+       struct thread **threadref;
+};
+
+/* Flags for task cancellation */
+#define THREAD_CANCEL_FLAG_READY     0x01
+
+static int thread_timer_cmp(const struct thread *a, const struct thread *b)
+{
+       if (a->u.sands.tv_sec < b->u.sands.tv_sec)
+               return -1;
+       if (a->u.sands.tv_sec > b->u.sands.tv_sec)
+               return 1;
+       if (a->u.sands.tv_usec < b->u.sands.tv_usec)
+               return -1;
+       if (a->u.sands.tv_usec > b->u.sands.tv_usec)
+               return 1;
+       return 0;
+}
+
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp);
+
+#if defined(__APPLE__)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+
+#define AWAKEN(m)                                                              \
+       do {                                                                   \
+               const unsigned char wakebyte = 0x01;                           \
+               write(m->io_pipe[1], &wakebyte, 1);                            \
+       } while (0);
+
+/* control variable for initializer */
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+pthread_key_t thread_current;
+
+static pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
+static struct list *masters;
+
+static void thread_free(struct thread_master *master, struct thread *thread);
+
+#ifndef EXCLUDE_CPU_TIME
+#define EXCLUDE_CPU_TIME 0
+#endif
+#ifndef CONSUMED_TIME_CHECK
+#define CONSUMED_TIME_CHECK 0
+#endif
+
+bool cputime_enabled = !EXCLUDE_CPU_TIME;
+unsigned long cputime_threshold = CONSUMED_TIME_CHECK;
+unsigned long walltime_threshold = CONSUMED_TIME_CHECK;
+
+/* CLI start ---------------------------------------------------------------- */
+#include "lib/event_clippy.c"
+
+static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
+{
+       int size = sizeof(a->func);
+
+       return jhash(&a->func, size, 0);
+}
+
+static bool cpu_record_hash_cmp(const struct cpu_thread_history *a,
+                              const struct cpu_thread_history *b)
+{
+       return a->func == b->func;
+}
+
+static void *cpu_record_hash_alloc(struct cpu_thread_history *a)
+{
+       struct cpu_thread_history *new;
+       new = XCALLOC(MTYPE_THREAD_STATS, sizeof(struct cpu_thread_history));
+       new->func = a->func;
+       new->funcname = a->funcname;
+       return new;
+}
+
+static void cpu_record_hash_free(void *a)
+{
+       struct cpu_thread_history *hist = a;
+
+       XFREE(MTYPE_THREAD_STATS, hist);
+}
+
+static void vty_out_cpu_thread_history(struct vty *vty,
+                                      struct cpu_thread_history *a)
+{
+       vty_out(vty,
+               "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu %10zu",
+               a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
+               a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
+               (a->real.total / a->total_calls), a->real.max,
+               a->total_cpu_warn, a->total_wall_warn, a->total_starv_warn);
+       vty_out(vty, "  %c%c%c%c%c  %s\n",
+               a->types & (1 << THREAD_READ) ? 'R' : ' ',
+               a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
+               a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
+               a->types & (1 << THREAD_EVENT) ? 'E' : ' ',
+               a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname);
+}
+
+static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[])
+{
+       struct cpu_thread_history *totals = args[0];
+       struct cpu_thread_history copy;
+       struct vty *vty = args[1];
+       uint8_t *filter = args[2];
+
+       struct cpu_thread_history *a = bucket->data;
+
+       copy.total_active =
+               atomic_load_explicit(&a->total_active, memory_order_seq_cst);
+       copy.total_calls =
+               atomic_load_explicit(&a->total_calls, memory_order_seq_cst);
+       copy.total_cpu_warn =
+               atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst);
+       copy.total_wall_warn =
+               atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst);
+       copy.total_starv_warn = atomic_load_explicit(&a->total_starv_warn,
+                                                    memory_order_seq_cst);
+       copy.cpu.total =
+               atomic_load_explicit(&a->cpu.total, memory_order_seq_cst);
+       copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst);
+       copy.real.total =
+               atomic_load_explicit(&a->real.total, memory_order_seq_cst);
+       copy.real.max =
+               atomic_load_explicit(&a->real.max, memory_order_seq_cst);
+       copy.types = atomic_load_explicit(&a->types, memory_order_seq_cst);
+       copy.funcname = a->funcname;
+
+       if (!(copy.types & *filter))
+               return;
+
+       vty_out_cpu_thread_history(vty, &copy);
+       totals->total_active += copy.total_active;
+       totals->total_calls += copy.total_calls;
+       totals->total_cpu_warn += copy.total_cpu_warn;
+       totals->total_wall_warn += copy.total_wall_warn;
+       totals->total_starv_warn += copy.total_starv_warn;
+       totals->real.total += copy.real.total;
+       if (totals->real.max < copy.real.max)
+               totals->real.max = copy.real.max;
+       totals->cpu.total += copy.cpu.total;
+       if (totals->cpu.max < copy.cpu.max)
+               totals->cpu.max = copy.cpu.max;
+}
+
+static void cpu_record_print(struct vty *vty, uint8_t filter)
+{
+       struct cpu_thread_history tmp;
+       void *args[3] = {&tmp, vty, &filter};
+       struct thread_master *m;
+       struct listnode *ln;
+
+       if (!cputime_enabled)
+               vty_out(vty,
+                       "\n"
+                       "Collecting CPU time statistics is currently disabled.  Following statistics\n"
+                       "will be zero or may display data from when collection was enabled.  Use the\n"
+                       "  \"service cputime-stats\"  command to start collecting data.\n"
+                       "\nCounters and wallclock times are always maintained and should be accurate.\n");
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.funcname = "TOTAL";
+       tmp.types = filter;
+
+       frr_with_mutex (&masters_mtx) {
+               for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
+                       const char *name = m->name ? m->name : "main";
+
+                       char underline[strlen(name) + 1];
+                       memset(underline, '-', sizeof(underline));
+                       underline[sizeof(underline) - 1] = '\0';
+
+                       vty_out(vty, "\n");
+                       vty_out(vty, "Showing statistics for pthread %s\n",
+                               name);
+                       vty_out(vty, "-------------------------------%s\n",
+                               underline);
+                       vty_out(vty, "%30s %18s %18s\n", "",
+                               "CPU (user+system):", "Real (wall-clock):");
+                       vty_out(vty,
+                               "Active   Runtime(ms)   Invoked Avg uSec Max uSecs");
+                       vty_out(vty, " Avg uSec Max uSecs");
+                       vty_out(vty,
+                               "  CPU_Warn Wall_Warn Starv_Warn Type   Thread\n");
+
+                       if (m->cpu_record->count)
+                               hash_iterate(
+                                       m->cpu_record,
+                                       (void (*)(struct hash_bucket *,
+                                                 void *))cpu_record_hash_print,
+                                       args);
+                       else
+                               vty_out(vty, "No data to display yet.\n");
+
+                       vty_out(vty, "\n");
+               }
+       }
+
+       vty_out(vty, "\n");
+       vty_out(vty, "Total thread statistics\n");
+       vty_out(vty, "-------------------------\n");
+       vty_out(vty, "%30s %18s %18s\n", "",
+               "CPU (user+system):", "Real (wall-clock):");
+       vty_out(vty, "Active   Runtime(ms)   Invoked Avg uSec Max uSecs");
+       vty_out(vty, " Avg uSec Max uSecs  CPU_Warn Wall_Warn");
+       vty_out(vty, "  Type  Thread\n");
+
+       if (tmp.total_calls > 0)
+               vty_out_cpu_thread_history(vty, &tmp);
+}
+
+static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[])
+{
+       uint8_t *filter = args[0];
+       struct hash *cpu_record = args[1];
+
+       struct cpu_thread_history *a = bucket->data;
+
+       if (!(a->types & *filter))
+               return;
+
+       hash_release(cpu_record, bucket->data);
+}
+
+static void cpu_record_clear(uint8_t filter)
+{
+       uint8_t *tmp = &filter;
+       struct thread_master *m;
+       struct listnode *ln;
+
+       frr_with_mutex (&masters_mtx) {
+               for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
+                       frr_with_mutex (&m->mtx) {
+                               void *args[2] = {tmp, m->cpu_record};
+                               hash_iterate(
+                                       m->cpu_record,
+                                       (void (*)(struct hash_bucket *,
+                                                 void *))cpu_record_hash_clear,
+                                       args);
+                       }
+               }
+       }
+}
+
+static uint8_t parse_filter(const char *filterstr)
+{
+       int i = 0;
+       int filter = 0;
+
+       while (filterstr[i] != '\0') {
+               switch (filterstr[i]) {
+               case 'r':
+               case 'R':
+                       filter |= (1 << THREAD_READ);
+                       break;
+               case 'w':
+               case 'W':
+                       filter |= (1 << THREAD_WRITE);
+                       break;
+               case 't':
+               case 'T':
+                       filter |= (1 << THREAD_TIMER);
+                       break;
+               case 'e':
+               case 'E':
+                       filter |= (1 << THREAD_EVENT);
+                       break;
+               case 'x':
+               case 'X':
+                       filter |= (1 << THREAD_EXECUTE);
+                       break;
+               default:
+                       break;
+               }
+               ++i;
+       }
+       return filter;
+}
+
+DEFUN_NOSH (show_thread_cpu,
+           show_thread_cpu_cmd,
+           "show thread cpu [FILTER]",
+           SHOW_STR
+           "Thread information\n"
+           "Thread CPU usage\n"
+           "Display filter (rwtex)\n")
+{
+       uint8_t filter = (uint8_t)-1U;
+       int idx = 0;
+
+       if (argv_find(argv, argc, "FILTER", &idx)) {
+               filter = parse_filter(argv[idx]->arg);
+               if (!filter) {
+                       vty_out(vty,
+                               "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
+                               argv[idx]->arg);
+                       return CMD_WARNING;
+               }
+       }
+
+       cpu_record_print(vty, filter);
+       return CMD_SUCCESS;
+}
+
+DEFPY (service_cputime_stats,
+       service_cputime_stats_cmd,
+       "[no] service cputime-stats",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Collect CPU usage statistics\n")
+{
+       cputime_enabled = !no;
+       return CMD_SUCCESS;
+}
+
+DEFPY (service_cputime_warning,
+       service_cputime_warning_cmd,
+       "[no] service cputime-warning (1-4294967295)",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Warn for tasks exceeding CPU usage threshold\n"
+       "Warning threshold in milliseconds\n")
+{
+       if (no)
+               cputime_threshold = 0;
+       else
+               cputime_threshold = cputime_warning * 1000;
+       return CMD_SUCCESS;
+}
+
+ALIAS (service_cputime_warning,
+       no_service_cputime_warning_cmd,
+       "no service cputime-warning",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Warn for tasks exceeding CPU usage threshold\n")
+
+DEFPY (service_walltime_warning,
+       service_walltime_warning_cmd,
+       "[no] service walltime-warning (1-4294967295)",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Warn for tasks exceeding total wallclock threshold\n"
+       "Warning threshold in milliseconds\n")
+{
+       if (no)
+               walltime_threshold = 0;
+       else
+               walltime_threshold = walltime_warning * 1000;
+       return CMD_SUCCESS;
+}
+
+ALIAS (service_walltime_warning,
+       no_service_walltime_warning_cmd,
+       "no service walltime-warning",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Warn for tasks exceeding total wallclock threshold\n")
+
+static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
+{
+       const char *name = m->name ? m->name : "main";
+       char underline[strlen(name) + 1];
+       struct thread *thread;
+       uint32_t i;
+
+       memset(underline, '-', sizeof(underline));
+       underline[sizeof(underline) - 1] = '\0';
+
+       vty_out(vty, "\nShowing poll FD's for %s\n", name);
+       vty_out(vty, "----------------------%s\n", underline);
+       vty_out(vty, "Count: %u/%d\n", (uint32_t)m->handler.pfdcount,
+               m->fd_limit);
+       for (i = 0; i < m->handler.pfdcount; i++) {
+               vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\t\t", i,
+                       m->handler.pfds[i].fd, m->handler.pfds[i].events,
+                       m->handler.pfds[i].revents);
+
+               if (m->handler.pfds[i].events & POLLIN) {
+                       thread = m->read[m->handler.pfds[i].fd];
+
+                       if (!thread)
+                               vty_out(vty, "ERROR ");
+                       else
+                               vty_out(vty, "%s ", thread->xref->funcname);
+               } else
+                       vty_out(vty, " ");
+
+               if (m->handler.pfds[i].events & POLLOUT) {
+                       thread = m->write[m->handler.pfds[i].fd];
+
+                       if (!thread)
+                               vty_out(vty, "ERROR\n");
+                       else
+                               vty_out(vty, "%s\n", thread->xref->funcname);
+               } else
+                       vty_out(vty, "\n");
+       }
+}
+
+DEFUN_NOSH (show_thread_poll,
+           show_thread_poll_cmd,
+           "show thread poll",
+           SHOW_STR
+           "Thread information\n"
+           "Show poll FD's and information\n")
+{
+       struct listnode *node;
+       struct thread_master *m;
+
+       frr_with_mutex (&masters_mtx) {
+               for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
+                       show_thread_poll_helper(vty, m);
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
+
+DEFUN (clear_thread_cpu,
+       clear_thread_cpu_cmd,
+       "clear thread cpu [FILTER]",
+       "Clear stored data in all pthreads\n"
+       "Thread information\n"
+       "Thread CPU usage\n"
+       "Display filter (rwtexb)\n")
+{
+       uint8_t filter = (uint8_t)-1U;
+       int idx = 0;
+
+       if (argv_find(argv, argc, "FILTER", &idx)) {
+               filter = parse_filter(argv[idx]->arg);
+               if (!filter) {
+                       vty_out(vty,
+                               "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
+                               argv[idx]->arg);
+                       return CMD_WARNING;
+               }
+       }
+
+       cpu_record_clear(filter);
+       return CMD_SUCCESS;
+}
+
+static void show_thread_timers_helper(struct vty *vty, struct thread_master *m)
+{
+       const char *name = m->name ? m->name : "main";
+       char underline[strlen(name) + 1];
+       struct thread *thread;
+
+       memset(underline, '-', sizeof(underline));
+       underline[sizeof(underline) - 1] = '\0';
+
+       vty_out(vty, "\nShowing timers for %s\n", name);
+       vty_out(vty, "-------------------%s\n", underline);
+
+       frr_each (thread_timer_list, &m->timer, thread) {
+               vty_out(vty, "  %-50s%pTH\n", thread->hist->funcname, thread);
+       }
+}
+
+DEFPY_NOSH (show_thread_timers,
+           show_thread_timers_cmd,
+           "show thread timers",
+           SHOW_STR
+           "Thread information\n"
+           "Show all timers and how long they have in the system\n")
+{
+       struct listnode *node;
+       struct thread_master *m;
+
+       frr_with_mutex (&masters_mtx) {
+               for (ALL_LIST_ELEMENTS_RO(masters, node, m))
+                       show_thread_timers_helper(vty, m);
+       }
+
+       return CMD_SUCCESS;
+}
+
+void thread_cmd_init(void)
+{
+       install_element(VIEW_NODE, &show_thread_cpu_cmd);
+       install_element(VIEW_NODE, &show_thread_poll_cmd);
+       install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
+
+       install_element(CONFIG_NODE, &service_cputime_stats_cmd);
+       install_element(CONFIG_NODE, &service_cputime_warning_cmd);
+       install_element(CONFIG_NODE, &no_service_cputime_warning_cmd);
+       install_element(CONFIG_NODE, &service_walltime_warning_cmd);
+       install_element(CONFIG_NODE, &no_service_walltime_warning_cmd);
+
+       install_element(VIEW_NODE, &show_thread_timers_cmd);
+}
+/* CLI end ------------------------------------------------------------------ */
+
+
+static void cancelreq_del(void *cr)
+{
+       XFREE(MTYPE_TMP, cr);
+}
+
+/* initializer, only ever called once */
+static void initializer(void)
+{
+       pthread_key_create(&thread_current, NULL);
+}
+
+struct thread_master *thread_master_create(const char *name)
+{
+       struct thread_master *rv;
+       struct rlimit limit;
+
+       pthread_once(&init_once, &initializer);
+
+       rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
+
+       /* Initialize master mutex */
+       pthread_mutex_init(&rv->mtx, NULL);
+       pthread_cond_init(&rv->cancel_cond, NULL);
+
+       /* Set name */
+       name = name ? name : "default";
+       rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
+
+       /* Initialize I/O task data structures */
+
+       /* Use configured limit if present, ulimit otherwise. */
+       rv->fd_limit = frr_get_fd_limit();
+       if (rv->fd_limit == 0) {
+               getrlimit(RLIMIT_NOFILE, &limit);
+               rv->fd_limit = (int)limit.rlim_cur;
+       }
+
+       rv->read = XCALLOC(MTYPE_THREAD_POLL,
+                          sizeof(struct thread *) * rv->fd_limit);
+
+       rv->write = XCALLOC(MTYPE_THREAD_POLL,
+                           sizeof(struct thread *) * rv->fd_limit);
+
+       char tmhashname[strlen(name) + 32];
+       snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash",
+                name);
+       rv->cpu_record = hash_create_size(
+               8, (unsigned int (*)(const void *))cpu_record_hash_key,
+               (bool (*)(const void *, const void *))cpu_record_hash_cmp,
+               tmhashname);
+
+       thread_list_init(&rv->event);
+       thread_list_init(&rv->ready);
+       thread_list_init(&rv->unuse);
+       thread_timer_list_init(&rv->timer);
+
+       /* Initialize thread_fetch() settings */
+       rv->spin = true;
+       rv->handle_signals = true;
+
+       /* Set pthread owner, should be updated by actual owner */
+       rv->owner = pthread_self();
+       rv->cancel_req = list_new();
+       rv->cancel_req->del = cancelreq_del;
+       rv->canceled = true;
+
+       /* Initialize pipe poker */
+       pipe(rv->io_pipe);
+       set_nonblocking(rv->io_pipe[0]);
+       set_nonblocking(rv->io_pipe[1]);
+
+       /* Initialize data structures for poll() */
+       rv->handler.pfdsize = rv->fd_limit;
+       rv->handler.pfdcount = 0;
+       rv->handler.pfds = XCALLOC(MTYPE_THREAD_MASTER,
+                                  sizeof(struct pollfd) * rv->handler.pfdsize);
+       rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER,
+                                  sizeof(struct pollfd) * rv->handler.pfdsize);
+
+       /* add to list of threadmasters */
+       frr_with_mutex (&masters_mtx) {
+               if (!masters)
+                       masters = list_new();
+
+               listnode_add(masters, rv);
+       }
+
+       return rv;
+}
+
+void thread_master_set_name(struct thread_master *master, const char *name)
+{
+       frr_with_mutex (&master->mtx) {
+               XFREE(MTYPE_THREAD_MASTER, master->name);
+               master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
+       }
+}
+
+#define THREAD_UNUSED_DEPTH 10
+
+/* Move thread to unuse list. */
+static void thread_add_unuse(struct thread_master *m, struct thread *thread)
+{
+       pthread_mutex_t mtxc = thread->mtx;
+
+       assert(m != NULL && thread != NULL);
+
+       thread->hist->total_active--;
+       memset(thread, 0, sizeof(struct thread));
+       thread->type = THREAD_UNUSED;
+
+       /* Restore the thread mutex context. */
+       thread->mtx = mtxc;
+
+       if (thread_list_count(&m->unuse) < THREAD_UNUSED_DEPTH) {
+               thread_list_add_tail(&m->unuse, thread);
+               return;
+       }
+
+       thread_free(m, thread);
+}
+
+/* Free all unused thread. */
+static void thread_list_free(struct thread_master *m,
+               struct thread_list_head *list)
+{
+       struct thread *t;
+
+       while ((t = thread_list_pop(list)))
+               thread_free(m, t);
+}
+
+static void thread_array_free(struct thread_master *m,
+                             struct thread **thread_array)
+{
+       struct thread *t;
+       int index;
+
+       for (index = 0; index < m->fd_limit; ++index) {
+               t = thread_array[index];
+               if (t) {
+                       thread_array[index] = NULL;
+                       thread_free(m, t);
+               }
+       }
+       XFREE(MTYPE_THREAD_POLL, thread_array);
+}
+
+/*
+ * thread_master_free_unused
+ *
+ * As threads are finished with they are put on the
+ * unuse list for later reuse.
+ * If we are shutting down, Free up unused threads
+ * So we can see if we forget to shut anything off
+ */
+void thread_master_free_unused(struct thread_master *m)
+{
+       frr_with_mutex (&m->mtx) {
+               struct thread *t;
+               while ((t = thread_list_pop(&m->unuse)))
+                       thread_free(m, t);
+       }
+}
+
+/* Stop thread scheduler. */
+void thread_master_free(struct thread_master *m)
+{
+       struct thread *t;
+
+       frr_with_mutex (&masters_mtx) {
+               listnode_delete(masters, m);
+               if (masters->count == 0) {
+                       list_delete(&masters);
+               }
+       }
+
+       thread_array_free(m, m->read);
+       thread_array_free(m, m->write);
+       while ((t = thread_timer_list_pop(&m->timer)))
+               thread_free(m, t);
+       thread_list_free(m, &m->event);
+       thread_list_free(m, &m->ready);
+       thread_list_free(m, &m->unuse);
+       pthread_mutex_destroy(&m->mtx);
+       pthread_cond_destroy(&m->cancel_cond);
+       close(m->io_pipe[0]);
+       close(m->io_pipe[1]);
+       list_delete(&m->cancel_req);
+       m->cancel_req = NULL;
+
+       hash_clean_and_free(&m->cpu_record, cpu_record_hash_free);
+
+       XFREE(MTYPE_THREAD_MASTER, m->name);
+       XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
+       XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
+       XFREE(MTYPE_THREAD_MASTER, m);
+}
+
+/* Return remain time in milliseconds. */
+unsigned long thread_timer_remain_msec(struct thread *thread)
+{
+       int64_t remain;
+
+       if (!thread_is_scheduled(thread))
+               return 0;
+
+       frr_with_mutex (&thread->mtx) {
+               remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
+       }
+
+       return remain < 0 ? 0 : remain;
+}
+
+/* Return remain time in seconds. */
+unsigned long thread_timer_remain_second(struct thread *thread)
+{
+       return thread_timer_remain_msec(thread) / 1000LL;
+}
+
+struct timeval thread_timer_remain(struct thread *thread)
+{
+       struct timeval remain;
+       frr_with_mutex (&thread->mtx) {
+               monotime_until(&thread->u.sands, &remain);
+       }
+       return remain;
+}
+
+static int time_hhmmss(char *buf, int buf_size, long sec)
+{
+       long hh;
+       long mm;
+       int wr;
+
+       assert(buf_size >= 8);
+
+       hh = sec / 3600;
+       sec %= 3600;
+       mm = sec / 60;
+       sec %= 60;
+
+       wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec);
+
+       return wr != 8;
+}
+
+char *thread_timer_to_hhmmss(char *buf, int buf_size,
+               struct thread *t_timer)
+{
+       if (t_timer) {
+               time_hhmmss(buf, buf_size,
+                               thread_timer_remain_second(t_timer));
+       } else {
+               snprintf(buf, buf_size, "--:--:--");
+       }
+       return buf;
+}
+
+/* Get new thread.  */
+static struct thread *thread_get(struct thread_master *m, uint8_t type,
+                                void (*func)(struct thread *), void *arg,
+                                const struct xref_threadsched *xref)
+{
+       struct thread *thread = thread_list_pop(&m->unuse);
+       struct cpu_thread_history tmp;
+
+       if (!thread) {
+               thread = XCALLOC(MTYPE_THREAD, sizeof(struct thread));
+               /* mutex only needs to be initialized at struct creation. */
+               pthread_mutex_init(&thread->mtx, NULL);
+               m->alloc++;
+       }
+
+       thread->type = type;
+       thread->add_type = type;
+       thread->master = m;
+       thread->arg = arg;
+       thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
+       thread->ref = NULL;
+       thread->ignore_timer_late = false;
+
+       /*
+        * So if the passed in funcname is not what we have
+        * stored that means the thread->hist needs to be
+        * updated.  We keep the last one around in unused
+        * under the assumption that we are probably
+        * going to immediately allocate the same
+        * type of thread.
+        * This hopefully saves us some serious
+        * hash_get lookups.
+        */
+       if ((thread->xref && thread->xref->funcname != xref->funcname)
+           || thread->func != func) {
+               tmp.func = func;
+               tmp.funcname = xref->funcname;
+               thread->hist =
+                       hash_get(m->cpu_record, &tmp,
+                                (void *(*)(void *))cpu_record_hash_alloc);
+       }
+       thread->hist->total_active++;
+       thread->func = func;
+       thread->xref = xref;
+
+       return thread;
+}
+
+static void thread_free(struct thread_master *master, struct thread *thread)
+{
+       /* Update statistics. */
+       assert(master->alloc > 0);
+       master->alloc--;
+
+       /* Free allocated resources. */
+       pthread_mutex_destroy(&thread->mtx);
+       XFREE(MTYPE_THREAD, thread);
+}
+
+static int fd_poll(struct thread_master *m, const struct timeval *timer_wait,
+                  bool *eintr_p)
+{
+       sigset_t origsigs;
+       unsigned char trash[64];
+       nfds_t count = m->handler.copycount;
+
+       /*
+        * If timer_wait is null here, that means poll() should block
+        * indefinitely, unless the thread_master has overridden it by setting
+        * ->selectpoll_timeout.
+        *
+        * If the value is positive, it specifies the maximum number of
+        * milliseconds to wait. If the timeout is -1, it specifies that
+        * we should never wait and always return immediately even if no
+        * event is detected. If the value is zero, the behavior is default.
+        */
+       int timeout = -1;
+
+       /* number of file descriptors with events */
+       int num;
+
+       if (timer_wait != NULL
+           && m->selectpoll_timeout == 0) // use the default value
+               timeout = (timer_wait->tv_sec * 1000)
+                         + (timer_wait->tv_usec / 1000);
+       else if (m->selectpoll_timeout > 0) // use the user's timeout
+               timeout = m->selectpoll_timeout;
+       else if (m->selectpoll_timeout
+                < 0) // effect a poll (return immediately)
+               timeout = 0;
+
+       zlog_tls_buffer_flush();
+       rcu_read_unlock();
+       rcu_assert_read_unlocked();
+
+       /* add poll pipe poker */
+       assert(count + 1 < m->handler.pfdsize);
+       m->handler.copy[count].fd = m->io_pipe[0];
+       m->handler.copy[count].events = POLLIN;
+       m->handler.copy[count].revents = 0x00;
+
+       /* We need to deal with a signal-handling race here: we
+        * don't want to miss a crucial signal, such as SIGTERM or SIGINT,
+        * that may arrive just before we enter poll(). We will block the
+        * key signals, then check whether any have arrived - if so, we return
+        * before calling poll(). If not, we'll re-enable the signals
+        * in the ppoll() call.
+        */
+
+       sigemptyset(&origsigs);
+       if (m->handle_signals) {
+               /* Main pthread that handles the app signals */
+               if (frr_sigevent_check(&origsigs)) {
+                       /* Signal to process - restore signal mask and return */
+                       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+                       num = -1;
+                       *eintr_p = true;
+                       goto done;
+               }
+       } else {
+               /* Don't make any changes for the non-main pthreads */
+               pthread_sigmask(SIG_SETMASK, NULL, &origsigs);
+       }
+
+#if defined(HAVE_PPOLL)
+       struct timespec ts, *tsp;
+
+       if (timeout >= 0) {
+               ts.tv_sec = timeout / 1000;
+               ts.tv_nsec = (timeout % 1000) * 1000000;
+               tsp = &ts;
+       } else
+               tsp = NULL;
+
+       num = ppoll(m->handler.copy, count + 1, tsp, &origsigs);
+       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+#else
+       /* Not ideal - there is a race after we restore the signal mask */
+       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+       num = poll(m->handler.copy, count + 1, timeout);
+#endif
+
+done:
+
+       if (num < 0 && errno == EINTR)
+               *eintr_p = true;
+
+       if (num > 0 && m->handler.copy[count].revents != 0 && num--)
+               while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
+                       ;
+
+       rcu_read_lock();
+
+       return num;
+}
+
+/* Add new read thread. */
+void _thread_add_read_write(const struct xref_threadsched *xref,
+                           struct thread_master *m,
+                           void (*func)(struct thread *), void *arg, int fd,
+                           struct thread **t_ptr)
+{
+       int dir = xref->thread_type;
+       struct thread *thread = NULL;
+       struct thread **thread_array;
+
+       if (dir == THREAD_READ)
+               frrtrace(9, frr_libfrr, schedule_read, m,
+                        xref->funcname, xref->xref.file, xref->xref.line,
+                        t_ptr, fd, 0, arg, 0);
+       else
+               frrtrace(9, frr_libfrr, schedule_write, m,
+                        xref->funcname, xref->xref.file, xref->xref.line,
+                        t_ptr, fd, 0, arg, 0);
+
+       assert(fd >= 0);
+       if (fd >= m->fd_limit)
+               assert(!"Number of FD's open is greater than FRR currently configured to handle, aborting");
+
+       frr_with_mutex (&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       // thread is already scheduled; don't reschedule
+                       break;
+
+               /* default to a new pollfd */
+               nfds_t queuepos = m->handler.pfdcount;
+
+               if (dir == THREAD_READ)
+                       thread_array = m->read;
+               else
+                       thread_array = m->write;
+
+               /* if we already have a pollfd for our file descriptor, find and
+                * use it */
+               for (nfds_t i = 0; i < m->handler.pfdcount; i++)
+                       if (m->handler.pfds[i].fd == fd) {
+                               queuepos = i;
+
+#ifdef DEV_BUILD
+                               /*
+                                * What happens if we have a thread already
+                                * created for this event?
+                                */
+                               if (thread_array[fd])
+                                       assert(!"Thread already scheduled for file descriptor");
+#endif
+                               break;
+                       }
+
+               /* make sure we have room for this fd + pipe poker fd */
+               assert(queuepos + 1 < m->handler.pfdsize);
+
+               thread = thread_get(m, dir, func, arg, xref);
+
+               m->handler.pfds[queuepos].fd = fd;
+               m->handler.pfds[queuepos].events |=
+                       (dir == THREAD_READ ? POLLIN : POLLOUT);
+
+               if (queuepos == m->handler.pfdcount)
+                       m->handler.pfdcount++;
+
+               if (thread) {
+                       frr_with_mutex (&thread->mtx) {
+                               thread->u.fd = fd;
+                               thread_array[thread->u.fd] = thread;
+                       }
+
+                       if (t_ptr) {
+                               *t_ptr = thread;
+                               thread->ref = t_ptr;
+                       }
+               }
+
+               AWAKEN(m);
+       }
+}
+
+static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
+                                     struct thread_master *m,
+                                     void (*func)(struct thread *), void *arg,
+                                     struct timeval *time_relative,
+                                     struct thread **t_ptr)
+{
+       struct thread *thread;
+       struct timeval t;
+
+       assert(m != NULL);
+
+       assert(time_relative);
+
+       frrtrace(9, frr_libfrr, schedule_timer, m,
+                xref->funcname, xref->xref.file, xref->xref.line,
+                t_ptr, 0, 0, arg, (long)time_relative->tv_sec);
+
+       /* Compute expiration/deadline time. */
+       monotime(&t);
+       timeradd(&t, time_relative, &t);
+
+       frr_with_mutex (&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       /* thread is already scheduled; don't reschedule */
+                       return;
+
+               thread = thread_get(m, THREAD_TIMER, func, arg, xref);
+
+               frr_with_mutex (&thread->mtx) {
+                       thread->u.sands = t;
+                       thread_timer_list_add(&m->timer, thread);
+                       if (t_ptr) {
+                               *t_ptr = thread;
+                               thread->ref = t_ptr;
+                       }
+               }
+
+               /* The timer list is sorted - if this new timer
+                * might change the time we'll wait for, give the pthread
+                * a chance to re-compute.
+                */
+               if (thread_timer_list_first(&m->timer) == thread)
+                       AWAKEN(m);
+       }
+#define ONEYEAR2SEC (60 * 60 * 24 * 365)
+       if (time_relative->tv_sec > ONEYEAR2SEC)
+               flog_err(
+                       EC_LIB_TIMER_TOO_LONG,
+                       "Timer: %pTHD is created with an expiration that is greater than 1 year",
+                       thread);
+}
+
+
+/* Add timer event thread. */
+void _thread_add_timer(const struct xref_threadsched *xref,
+                      struct thread_master *m, void (*func)(struct thread *),
+                      void *arg, long timer, struct thread **t_ptr)
+{
+       struct timeval trel;
+
+       assert(m != NULL);
+
+       trel.tv_sec = timer;
+       trel.tv_usec = 0;
+
+       _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
+}
+
+/* Add timer event thread with "millisecond" resolution */
+void _thread_add_timer_msec(const struct xref_threadsched *xref,
+                           struct thread_master *m,
+                           void (*func)(struct thread *), void *arg,
+                           long timer, struct thread **t_ptr)
+{
+       struct timeval trel;
+
+       assert(m != NULL);
+
+       trel.tv_sec = timer / 1000;
+       trel.tv_usec = 1000 * (timer % 1000);
+
+       _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
+}
+
+/* Add timer event thread with "timeval" resolution */
+void _thread_add_timer_tv(const struct xref_threadsched *xref,
+                         struct thread_master *m,
+                         void (*func)(struct thread *), void *arg,
+                         struct timeval *tv, struct thread **t_ptr)
+{
+       _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
+}
+
+/* Add simple event thread. */
+void _thread_add_event(const struct xref_threadsched *xref,
+                      struct thread_master *m, void (*func)(struct thread *),
+                      void *arg, int val, struct thread **t_ptr)
+{
+       struct thread *thread = NULL;
+
+       frrtrace(9, frr_libfrr, schedule_event, m,
+                xref->funcname, xref->xref.file, xref->xref.line,
+                t_ptr, 0, val, arg, 0);
+
+       assert(m != NULL);
+
+       frr_with_mutex (&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       /* thread is already scheduled; don't reschedule */
+                       break;
+
+               thread = thread_get(m, THREAD_EVENT, func, arg, xref);
+               frr_with_mutex (&thread->mtx) {
+                       thread->u.val = val;
+                       thread_list_add_tail(&m->event, thread);
+               }
+
+               if (t_ptr) {
+                       *t_ptr = thread;
+                       thread->ref = t_ptr;
+               }
+
+               AWAKEN(m);
+       }
+}
+
+/* Thread cancellation ------------------------------------------------------ */
+
+/**
+ * NOT's out the .events field of pollfd corresponding to the given file
+ * descriptor. The event to be NOT'd is passed in the 'state' parameter.
+ *
+ * This needs to happen for both copies of pollfd's. See 'thread_fetch'
+ * implementation for details.
+ *
+ * @param master
+ * @param fd
+ * @param state the event to cancel. One or more (OR'd together) of the
+ * following:
+ *   - POLLIN
+ *   - POLLOUT
+ */
+static void thread_cancel_rw(struct thread_master *master, int fd, short state,
+                            int idx_hint)
+{
+       bool found = false;
+
+       /* find the index of corresponding pollfd */
+       nfds_t i;
+
+       /* Cancel POLLHUP too just in case some bozo set it */
+       state |= POLLHUP;
+
+       /* Some callers know the index of the pfd already */
+       if (idx_hint >= 0) {
+               i = idx_hint;
+               found = true;
+       } else {
+               /* Have to look for the fd in the pfd array */
+               for (i = 0; i < master->handler.pfdcount; i++)
+                       if (master->handler.pfds[i].fd == fd) {
+                               found = true;
+                               break;
+                       }
+       }
+
+       if (!found) {
+               zlog_debug(
+                       "[!] Received cancellation request for nonexistent rw job");
+               zlog_debug("[!] threadmaster: %s | fd: %d",
+                          master->name ? master->name : "", fd);
+               return;
+       }
+
+       /* NOT out event. */
+       master->handler.pfds[i].events &= ~(state);
+
+       /* If all events are canceled, delete / resize the pollfd array. */
+       if (master->handler.pfds[i].events == 0) {
+               memmove(master->handler.pfds + i, master->handler.pfds + i + 1,
+                       (master->handler.pfdcount - i - 1)
+                               * sizeof(struct pollfd));
+               master->handler.pfdcount--;
+               master->handler.pfds[master->handler.pfdcount].fd = 0;
+               master->handler.pfds[master->handler.pfdcount].events = 0;
+       }
+
+       /* If we have the same pollfd in the copy, perform the same operations,
+        * otherwise return. */
+       if (i >= master->handler.copycount)
+               return;
+
+       master->handler.copy[i].events &= ~(state);
+
+       if (master->handler.copy[i].events == 0) {
+               memmove(master->handler.copy + i, master->handler.copy + i + 1,
+                       (master->handler.copycount - i - 1)
+                               * sizeof(struct pollfd));
+               master->handler.copycount--;
+               master->handler.copy[master->handler.copycount].fd = 0;
+               master->handler.copy[master->handler.copycount].events = 0;
+       }
+}
+
+/*
+ * Process task cancellation given a task argument: iterate through the
+ * various lists of tasks, looking for any that match the argument.
+ */
+static void cancel_arg_helper(struct thread_master *master,
+                             const struct cancel_req *cr)
+{
+       struct thread *t;
+       nfds_t i;
+       int fd;
+       struct pollfd *pfd;
+
+       /* We're only processing arg-based cancellations here. */
+       if (cr->eventobj == NULL)
+               return;
+
+       /* First process the ready lists. */
+       frr_each_safe(thread_list, &master->event, t) {
+               if (t->arg != cr->eventobj)
+                       continue;
+               thread_list_del(&master->event, t);
+               if (t->ref)
+                       *t->ref = NULL;
+               thread_add_unuse(master, t);
+       }
+
+       frr_each_safe(thread_list, &master->ready, t) {
+               if (t->arg != cr->eventobj)
+                       continue;
+               thread_list_del(&master->ready, t);
+               if (t->ref)
+                       *t->ref = NULL;
+               thread_add_unuse(master, t);
+       }
+
+       /* If requested, stop here and ignore io and timers */
+       if (CHECK_FLAG(cr->flags, THREAD_CANCEL_FLAG_READY))
+               return;
+
+       /* Check the io tasks */
+       for (i = 0; i < master->handler.pfdcount;) {
+               pfd = master->handler.pfds + i;
+
+               if (pfd->events & POLLIN)
+                       t = master->read[pfd->fd];
+               else
+                       t = master->write[pfd->fd];
+
+               if (t && t->arg == cr->eventobj) {
+                       fd = pfd->fd;
+
+                       /* Found a match to cancel: clean up fd arrays */
+                       thread_cancel_rw(master, pfd->fd, pfd->events, i);
+
+                       /* Clean up thread arrays */
+                       master->read[fd] = NULL;
+                       master->write[fd] = NULL;
+
+                       /* Clear caller's ref */
+                       if (t->ref)
+                               *t->ref = NULL;
+
+                       thread_add_unuse(master, t);
+
+                       /* Don't increment 'i' since the cancellation will have
+                        * removed the entry from the pfd array
+                        */
+               } else
+                       i++;
+       }
+
+       /* Check the timer tasks */
+       t = thread_timer_list_first(&master->timer);
+       while (t) {
+               struct thread *t_next;
+
+               t_next = thread_timer_list_next(&master->timer, t);
+
+               if (t->arg == cr->eventobj) {
+                       thread_timer_list_del(&master->timer, t);
+                       if (t->ref)
+                               *t->ref = NULL;
+                       thread_add_unuse(master, t);
+               }
+
+               t = t_next;
+       }
+}
+
+/**
+ * Process cancellation requests.
+ *
+ * This may only be run from the pthread which owns the thread_master.
+ *
+ * @param master the thread master to process
+ * @REQUIRE master->mtx
+ */
+static void do_thread_cancel(struct thread_master *master)
+{
+       struct thread_list_head *list = NULL;
+       struct thread **thread_array = NULL;
+       struct thread *thread;
+       struct cancel_req *cr;
+       struct listnode *ln;
+
+       for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
+               /*
+                * If this is an event object cancellation, search
+                * through task lists deleting any tasks which have the
+                * specified argument - use this handy helper function.
+                */
+               if (cr->eventobj) {
+                       cancel_arg_helper(master, cr);
+                       continue;
+               }
+
+               /*
+                * The pointer varies depending on whether the cancellation
+                * request was made asynchronously or not. If it was, we
+                * need to check whether the thread even exists anymore
+                * before cancelling it.
+                */
+               thread = (cr->thread) ? cr->thread : *cr->threadref;
+
+               if (!thread)
+                       continue;
+
+               list = NULL;
+               thread_array = NULL;
+
+               /* Determine the appropriate queue to cancel the thread from */
+               switch (thread->type) {
+               case THREAD_READ:
+                       thread_cancel_rw(master, thread->u.fd, POLLIN, -1);
+                       thread_array = master->read;
+                       break;
+               case THREAD_WRITE:
+                       thread_cancel_rw(master, thread->u.fd, POLLOUT, -1);
+                       thread_array = master->write;
+                       break;
+               case THREAD_TIMER:
+                       thread_timer_list_del(&master->timer, thread);
+                       break;
+               case THREAD_EVENT:
+                       list = &master->event;
+                       break;
+               case THREAD_READY:
+                       list = &master->ready;
+                       break;
+               default:
+                       continue;
+                       break;
+               }
+
+               if (list) {
+                       thread_list_del(list, thread);
+               } else if (thread_array) {
+                       thread_array[thread->u.fd] = NULL;
+               }
+
+               if (thread->ref)
+                       *thread->ref = NULL;
+
+               thread_add_unuse(thread->master, thread);
+       }
+
+       /* Delete and free all cancellation requests */
+       if (master->cancel_req)
+               list_delete_all_node(master->cancel_req);
+
+       /* Wake up any threads which may be blocked in thread_cancel_async() */
+       master->canceled = true;
+       pthread_cond_broadcast(&master->cancel_cond);
+}
+
+/*
+ * Helper function used for multiple flavors of arg-based cancellation.
+ */
+static void cancel_event_helper(struct thread_master *m, void *arg, int flags)
+{
+       struct cancel_req *cr;
+
+       assert(m->owner == pthread_self());
+
+       /* Only worth anything if caller supplies an arg. */
+       if (arg == NULL)
+               return;
+
+       cr = XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
+
+       cr->flags = flags;
+
+       frr_with_mutex (&m->mtx) {
+               cr->eventobj = arg;
+               listnode_add(m->cancel_req, cr);
+               do_thread_cancel(m);
+       }
+}
+
+/**
+ * Cancel any events which have the specified argument.
+ *
+ * MT-Unsafe
+ *
+ * @param m the thread_master to cancel from
+ * @param arg the argument passed when creating the event
+ */
+void thread_cancel_event(struct thread_master *master, void *arg)
+{
+       cancel_event_helper(master, arg, 0);
+}
+
+/*
+ * Cancel ready tasks with an arg matching 'arg'
+ *
+ * MT-Unsafe
+ *
+ * @param m the thread_master to cancel from
+ * @param arg the argument passed when creating the event
+ */
+void thread_cancel_event_ready(struct thread_master *m, void *arg)
+{
+
+       /* Only cancel ready/event tasks */
+       cancel_event_helper(m, arg, THREAD_CANCEL_FLAG_READY);
+}
+
+/**
+ * Cancel a specific task.
+ *
+ * MT-Unsafe
+ *
+ * @param thread task to cancel
+ */
+void thread_cancel(struct thread **thread)
+{
+       struct thread_master *master;
+
+       if (thread == NULL || *thread == NULL)
+               return;
+
+       master = (*thread)->master;
+
+       frrtrace(9, frr_libfrr, thread_cancel, master,
+                (*thread)->xref->funcname, (*thread)->xref->xref.file,
+                (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
+                (*thread)->u.val, (*thread)->arg, (*thread)->u.sands.tv_sec);
+
+       assert(master->owner == pthread_self());
+
+       frr_with_mutex (&master->mtx) {
+               struct cancel_req *cr =
+                       XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
+               cr->thread = *thread;
+               listnode_add(master->cancel_req, cr);
+               do_thread_cancel(master);
+       }
+
+       *thread = NULL;
+}
+
+/**
+ * Asynchronous cancellation.
+ *
+ * Called with either a struct thread ** or void * to an event argument,
+ * this function posts the correct cancellation request and blocks until it is
+ * serviced.
+ *
+ * If the thread is currently running, execution blocks until it completes.
+ *
+ * The last two parameters are mutually exclusive, i.e. if you pass one the
+ * other must be NULL.
+ *
+ * When the cancellation procedure executes on the target thread_master, the
+ * thread * provided is checked for nullity. If it is null, the thread is
+ * assumed to no longer exist and the cancellation request is a no-op. Thus
+ * users of this API must pass a back-reference when scheduling the original
+ * task.
+ *
+ * MT-Safe
+ *
+ * @param master the thread master with the relevant event / task
+ * @param thread pointer to thread to cancel
+ * @param eventobj the event
+ */
+void thread_cancel_async(struct thread_master *master, struct thread **thread,
+                        void *eventobj)
+{
+       assert(!(thread && eventobj) && (thread || eventobj));
+
+       if (thread && *thread)
+               frrtrace(9, frr_libfrr, thread_cancel_async, master,
+                        (*thread)->xref->funcname, (*thread)->xref->xref.file,
+                        (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
+                        (*thread)->u.val, (*thread)->arg,
+                        (*thread)->u.sands.tv_sec);
+       else
+               frrtrace(9, frr_libfrr, thread_cancel_async, master, NULL, NULL,
+                        0, NULL, 0, 0, eventobj, 0);
+
+       assert(master->owner != pthread_self());
+
+       frr_with_mutex (&master->mtx) {
+               master->canceled = false;
+
+               if (thread) {
+                       struct cancel_req *cr =
+                               XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
+                       cr->threadref = thread;
+                       listnode_add(master->cancel_req, cr);
+               } else if (eventobj) {
+                       struct cancel_req *cr =
+                               XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
+                       cr->eventobj = eventobj;
+                       listnode_add(master->cancel_req, cr);
+               }
+               AWAKEN(master);
+
+               while (!master->canceled)
+                       pthread_cond_wait(&master->cancel_cond, &master->mtx);
+       }
+
+       if (thread)
+               *thread = NULL;
+}
+/* ------------------------------------------------------------------------- */
+
+static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers,
+                                        struct timeval *timer_val)
+{
+       if (!thread_timer_list_count(timers))
+               return NULL;
+
+       struct thread *next_timer = thread_timer_list_first(timers);
+       monotime_until(&next_timer->u.sands, timer_val);
+       return timer_val;
+}
+
+static struct thread *thread_run(struct thread_master *m, struct thread *thread,
+                                struct thread *fetch)
+{
+       *fetch = *thread;
+       thread_add_unuse(m, thread);
+       return fetch;
+}
+
+static int thread_process_io_helper(struct thread_master *m,
+                                   struct thread *thread, short state,
+                                   short actual_state, int pos)
+{
+       struct thread **thread_array;
+
+       /*
+        * poll() clears the .events field, but the pollfd array we
+        * pass to poll() is a copy of the one used to schedule threads.
+        * We need to synchronize state between the two here by applying
+        * the same changes poll() made on the copy of the "real" pollfd
+        * array.
+        *
+        * This cleans up a possible infinite loop where we refuse
+        * to respond to a poll event but poll is insistent that
+        * we should.
+        */
+       m->handler.pfds[pos].events &= ~(state);
+
+       if (!thread) {
+               if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
+                       flog_err(EC_LIB_NO_THREAD,
+                                "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!",
+                                m->handler.pfds[pos].fd, actual_state);
+               return 0;
+       }
+
+       if (thread->type == THREAD_READ)
+               thread_array = m->read;
+       else
+               thread_array = m->write;
+
+       thread_array[thread->u.fd] = NULL;
+       thread_list_add_tail(&m->ready, thread);
+       thread->type = THREAD_READY;
+
+       return 1;
+}
+
+/**
+ * Process I/O events.
+ *
+ * Walks through file descriptor array looking for those pollfds whose .revents
+ * field has something interesting. Deletes any invalid file descriptors.
+ *
+ * @param m the thread master
+ * @param num the number of active file descriptors (return value of poll())
+ */
+static void thread_process_io(struct thread_master *m, unsigned int num)
+{
+       unsigned int ready = 0;
+       struct pollfd *pfds = m->handler.copy;
+
+       for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) {
+               /* no event for current fd? immediately continue */
+               if (pfds[i].revents == 0)
+                       continue;
+
+               ready++;
+
+               /*
+                * Unless someone has called thread_cancel from another
+                * pthread, the only thing that could have changed in
+                * m->handler.pfds while we were asleep is the .events
+                * field in a given pollfd. Barring thread_cancel() that
+                * value should be a superset of the values we have in our
+                * copy, so there's no need to update it. Similarily,
+                * barring deletion, the fd should still be a valid index
+                * into the master's pfds.
+                *
+                * We are including POLLERR here to do a READ event
+                * this is because the read should fail and the
+                * read function should handle it appropriately
+                */
+               if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
+                       thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
+                                                pfds[i].revents, i);
+               }
+               if (pfds[i].revents & POLLOUT)
+                       thread_process_io_helper(m, m->write[pfds[i].fd],
+                                                POLLOUT, pfds[i].revents, i);
+
+               /* if one of our file descriptors is garbage, remove the same
+                * from
+                * both pfds + update sizes and index */
+               if (pfds[i].revents & POLLNVAL) {
+                       memmove(m->handler.pfds + i, m->handler.pfds + i + 1,
+                               (m->handler.pfdcount - i - 1)
+                                       * sizeof(struct pollfd));
+                       m->handler.pfdcount--;
+                       m->handler.pfds[m->handler.pfdcount].fd = 0;
+                       m->handler.pfds[m->handler.pfdcount].events = 0;
+
+                       memmove(pfds + i, pfds + i + 1,
+                               (m->handler.copycount - i - 1)
+                                       * sizeof(struct pollfd));
+                       m->handler.copycount--;
+                       m->handler.copy[m->handler.copycount].fd = 0;
+                       m->handler.copy[m->handler.copycount].events = 0;
+
+                       i--;
+               }
+       }
+}
+
+/* Add all timers that have popped to the ready list. */
+static unsigned int thread_process_timers(struct thread_master *m,
+                                         struct timeval *timenow)
+{
+       struct timeval prev = *timenow;
+       bool displayed = false;
+       struct thread *thread;
+       unsigned int ready = 0;
+
+       while ((thread = thread_timer_list_first(&m->timer))) {
+               if (timercmp(timenow, &thread->u.sands, <))
+                       break;
+               prev = thread->u.sands;
+               prev.tv_sec += 4;
+               /*
+                * If the timer would have popped 4 seconds in the
+                * past then we are in a situation where we are
+                * really getting behind on handling of events.
+                * Let's log it and do the right thing with it.
+                */
+               if (timercmp(timenow, &prev, >)) {
+                       atomic_fetch_add_explicit(
+                               &thread->hist->total_starv_warn, 1,
+                               memory_order_seq_cst);
+                       if (!displayed && !thread->ignore_timer_late) {
+                               flog_warn(
+                                       EC_LIB_STARVE_THREAD,
+                                       "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago",
+                                       thread);
+                               displayed = true;
+                       }
+               }
+
+               thread_timer_list_pop(&m->timer);
+               thread->type = THREAD_READY;
+               thread_list_add_tail(&m->ready, thread);
+               ready++;
+       }
+
+       return ready;
+}
+
+/* process a list en masse, e.g. for event thread lists */
+static unsigned int thread_process(struct thread_list_head *list)
+{
+       struct thread *thread;
+       unsigned int ready = 0;
+
+       while ((thread = thread_list_pop(list))) {
+               thread->type = THREAD_READY;
+               thread_list_add_tail(&thread->master->ready, thread);
+               ready++;
+       }
+       return ready;
+}
+
+
+/* Fetch next ready thread. */
+struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
+{
+       struct thread *thread = NULL;
+       struct timeval now;
+       struct timeval zerotime = {0, 0};
+       struct timeval tv;
+       struct timeval *tw = NULL;
+       bool eintr_p = false;
+       int num = 0;
+
+       do {
+               /* Handle signals if any */
+               if (m->handle_signals)
+                       frr_sigevent_process();
+
+               pthread_mutex_lock(&m->mtx);
+
+               /* Process any pending cancellation requests */
+               do_thread_cancel(m);
+
+               /*
+                * Attempt to flush ready queue before going into poll().
+                * This is performance-critical. Think twice before modifying.
+                */
+               if ((thread = thread_list_pop(&m->ready))) {
+                       fetch = thread_run(m, thread, fetch);
+                       if (fetch->ref)
+                               *fetch->ref = NULL;
+                       pthread_mutex_unlock(&m->mtx);
+                       if (!m->ready_run_loop)
+                               GETRUSAGE(&m->last_getrusage);
+                       m->ready_run_loop = true;
+                       break;
+               }
+
+               m->ready_run_loop = false;
+               /* otherwise, tick through scheduling sequence */
+
+               /*
+                * Post events to ready queue. This must come before the
+                * following block since events should occur immediately
+                */
+               thread_process(&m->event);
+
+               /*
+                * If there are no tasks on the ready queue, we will poll()
+                * until a timer expires or we receive I/O, whichever comes
+                * first. The strategy for doing this is:
+                *
+                * - If there are events pending, set the poll() timeout to zero
+                * - If there are no events pending, but there are timers
+                * pending, set the timeout to the smallest remaining time on
+                * any timer.
+                * - If there are neither timers nor events pending, but there
+                * are file descriptors pending, block indefinitely in poll()
+                * - If nothing is pending, it's time for the application to die
+                *
+                * In every case except the last, we need to hit poll() at least
+                * once per loop to avoid starvation by events
+                */
+               if (!thread_list_count(&m->ready))
+                       tw = thread_timer_wait(&m->timer, &tv);
+
+               if (thread_list_count(&m->ready) ||
+                               (tw && !timercmp(tw, &zerotime, >)))
+                       tw = &zerotime;
+
+               if (!tw && m->handler.pfdcount == 0) { /* die */
+                       pthread_mutex_unlock(&m->mtx);
+                       fetch = NULL;
+                       break;
+               }
+
+               /*
+                * Copy pollfd array + # active pollfds in it. Not necessary to
+                * copy the array size as this is fixed.
+                */
+               m->handler.copycount = m->handler.pfdcount;
+               memcpy(m->handler.copy, m->handler.pfds,
+                      m->handler.copycount * sizeof(struct pollfd));
+
+               pthread_mutex_unlock(&m->mtx);
+               {
+                       eintr_p = false;
+                       num = fd_poll(m, tw, &eintr_p);
+               }
+               pthread_mutex_lock(&m->mtx);
+
+               /* Handle any errors received in poll() */
+               if (num < 0) {
+                       if (eintr_p) {
+                               pthread_mutex_unlock(&m->mtx);
+                               /* loop around to signal handler */
+                               continue;
+                       }
+
+                       /* else die */
+                       flog_err(EC_LIB_SYSTEM_CALL, "poll() error: %s",
+                                safe_strerror(errno));
+                       pthread_mutex_unlock(&m->mtx);
+                       fetch = NULL;
+                       break;
+               }
+
+               /* Post timers to ready queue. */
+               monotime(&now);
+               thread_process_timers(m, &now);
+
+               /* Post I/O to ready queue. */
+               if (num > 0)
+                       thread_process_io(m, num);
+
+               pthread_mutex_unlock(&m->mtx);
+
+       } while (!thread && m->spin);
+
+       return fetch;
+}
+
+static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
+{
+       return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+               + (a.tv_usec - b.tv_usec));
+}
+
+unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
+                                  unsigned long *cputime)
+{
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+
+#ifdef __FreeBSD__
+       /*
+        * FreeBSD appears to have an issue when calling clock_gettime
+        * with CLOCK_THREAD_CPUTIME_ID really close to each other
+        * occassionally the now time will be before the start time.
+        * This is not good and FRR is ending up with CPU HOG's
+        * when the subtraction wraps to very large numbers
+        *
+        * What we are going to do here is cheat a little bit
+        * and notice that this is a problem and just correct
+        * it so that it is impossible to happen
+        */
+       if (start->cpu.tv_sec == now->cpu.tv_sec &&
+           start->cpu.tv_nsec > now->cpu.tv_nsec)
+               now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+       else if (start->cpu.tv_sec > now->cpu.tv_sec) {
+               now->cpu.tv_sec = start->cpu.tv_sec;
+               now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
+       }
+#endif
+       *cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO
+                  + (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000;
+#else
+       /* This is 'user + sys' time.  */
+       *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
+                  + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
+#endif
+       return timeval_elapsed(now->real, start->real);
+}
+
+/* We should aim to yield after yield milliseconds, which defaults
+   to THREAD_YIELD_TIME_SLOT .
+   Note: we are using real (wall clock) time for this calculation.
+   It could be argued that CPU time may make more sense in certain
+   contexts.  The things to consider are whether the thread may have
+   blocked (in which case wall time increases, but CPU time does not),
+   or whether the system is heavily loaded with other processes competing
+   for CPU time.  On balance, wall clock time seems to make sense.
+   Plus it has the added benefit that gettimeofday should be faster
+   than calling getrusage. */
+int thread_should_yield(struct thread *thread)
+{
+       int result;
+       frr_with_mutex (&thread->mtx) {
+               result = monotime_since(&thread->real, NULL)
+                        > (int64_t)thread->yield;
+       }
+       return result;
+}
+
+void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
+{
+       frr_with_mutex (&thread->mtx) {
+               thread->yield = yield_time;
+       }
+}
+
+void thread_getrusage(RUSAGE_T *r)
+{
+       monotime(&r->real);
+       if (!cputime_enabled) {
+               memset(&r->cpu, 0, sizeof(r->cpu));
+               return;
+       }
+
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+       /* not currently implemented in Linux's vDSO, but maybe at some point
+        * in the future?
+        */
+       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &r->cpu);
+#else /* !HAVE_CLOCK_THREAD_CPUTIME_ID */
+#if defined RUSAGE_THREAD
+#define FRR_RUSAGE RUSAGE_THREAD
+#else
+#define FRR_RUSAGE RUSAGE_SELF
+#endif
+       getrusage(FRR_RUSAGE, &(r->cpu));
+#endif
+}
+
+/*
+ * Call a thread.
+ *
+ * This function will atomically update the thread's usage history. At present
+ * this is the only spot where usage history is written. Nevertheless the code
+ * has been written such that the introduction of writers in the future should
+ * not need to update it provided the writers atomically perform only the
+ * operations done here, i.e. updating the total and maximum times. In
+ * particular, the maximum real and cpu times must be monotonically increasing
+ * or this code is not correct.
+ */
+void thread_call(struct thread *thread)
+{
+       RUSAGE_T before, after;
+
+       /* if the thread being called is the CLI, it may change cputime_enabled
+        * ("service cputime-stats" command), which can result in nonsensical
+        * and very confusing warnings
+        */
+       bool cputime_enabled_here = cputime_enabled;
+
+       if (thread->master->ready_run_loop)
+               before = thread->master->last_getrusage;
+       else
+               GETRUSAGE(&before);
+
+       thread->real = before.real;
+
+       frrtrace(9, frr_libfrr, thread_call, thread->master,
+                thread->xref->funcname, thread->xref->xref.file,
+                thread->xref->xref.line, NULL, thread->u.fd,
+                thread->u.val, thread->arg, thread->u.sands.tv_sec);
+
+       pthread_setspecific(thread_current, thread);
+       (*thread->func)(thread);
+       pthread_setspecific(thread_current, NULL);
+
+       GETRUSAGE(&after);
+       thread->master->last_getrusage = after;
+
+       unsigned long walltime, cputime;
+       unsigned long exp;
+
+       walltime = thread_consumed_time(&after, &before, &cputime);
+
+       /* update walltime */
+       atomic_fetch_add_explicit(&thread->hist->real.total, walltime,
+                                 memory_order_seq_cst);
+       exp = atomic_load_explicit(&thread->hist->real.max,
+                                  memory_order_seq_cst);
+       while (exp < walltime
+              && !atomic_compare_exchange_weak_explicit(
+                      &thread->hist->real.max, &exp, walltime,
+                      memory_order_seq_cst, memory_order_seq_cst))
+               ;
+
+       if (cputime_enabled_here && cputime_enabled) {
+               /* update cputime */
+               atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime,
+                                         memory_order_seq_cst);
+               exp = atomic_load_explicit(&thread->hist->cpu.max,
+                                          memory_order_seq_cst);
+               while (exp < cputime
+                      && !atomic_compare_exchange_weak_explicit(
+                              &thread->hist->cpu.max, &exp, cputime,
+                              memory_order_seq_cst, memory_order_seq_cst))
+                       ;
+       }
+
+       atomic_fetch_add_explicit(&thread->hist->total_calls, 1,
+                                 memory_order_seq_cst);
+       atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type,
+                                memory_order_seq_cst);
+
+       if (cputime_enabled_here && cputime_enabled && cputime_threshold
+           && cputime > cputime_threshold) {
+               /*
+                * We have a CPU Hog on our hands.  The time FRR has spent
+                * doing actual work (not sleeping) is greater than 5 seconds.
+                * Whinge about it now, so we're aware this is yet another task
+                * to fix.
+                */
+               atomic_fetch_add_explicit(&thread->hist->total_cpu_warn,
+                                         1, memory_order_seq_cst);
+               flog_warn(
+                       EC_LIB_SLOW_THREAD_CPU,
+                       "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)",
+                       thread->xref->funcname, (unsigned long)thread->func,
+                       walltime / 1000, cputime / 1000);
+
+       } else if (walltime_threshold && walltime > walltime_threshold) {
+               /*
+                * The runtime for a task is greater than 5 seconds, but the
+                * cpu time is under 5 seconds.  Let's whine about this because
+                * this could imply some sort of scheduling issue.
+                */
+               atomic_fetch_add_explicit(&thread->hist->total_wall_warn,
+                                         1, memory_order_seq_cst);
+               flog_warn(
+                       EC_LIB_SLOW_THREAD_WALL,
+                       "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)",
+                       thread->xref->funcname, (unsigned long)thread->func,
+                       walltime / 1000, cputime / 1000);
+       }
+}
+
+/* Execute thread */
+void _thread_execute(const struct xref_threadsched *xref,
+                    struct thread_master *m, void (*func)(struct thread *),
+                    void *arg, int val)
+{
+       struct thread *thread;
+
+       /* Get or allocate new thread to execute. */
+       frr_with_mutex (&m->mtx) {
+               thread = thread_get(m, THREAD_EVENT, func, arg, xref);
+
+               /* Set its event value. */
+               frr_with_mutex (&thread->mtx) {
+                       thread->add_type = THREAD_EXECUTE;
+                       thread->u.val = val;
+                       thread->ref = &thread;
+               }
+       }
+
+       /* Execute thread doing all accounting. */
+       thread_call(thread);
+
+       /* Give back or free thread. */
+       thread_add_unuse(m, thread);
+}
+
+/* Debug signal mask - if 'sigs' is NULL, use current effective mask. */
+void debug_signals(const sigset_t *sigs)
+{
+       int i, found;
+       sigset_t tmpsigs;
+       char buf[300];
+
+       /*
+        * We're only looking at the non-realtime signals here, so we need
+        * some limit value. Platform differences mean at some point we just
+        * need to pick a reasonable value.
+        */
+#if defined SIGRTMIN
+#  define LAST_SIGNAL SIGRTMIN
+#else
+#  define LAST_SIGNAL 32
+#endif
+
+
+       if (sigs == NULL) {
+               sigemptyset(&tmpsigs);
+               pthread_sigmask(SIG_BLOCK, NULL, &tmpsigs);
+               sigs = &tmpsigs;
+       }
+
+       found = 0;
+       buf[0] = '\0';
+
+       for (i = 0; i < LAST_SIGNAL; i++) {
+               char tmp[20];
+
+               if (sigismember(sigs, i) > 0) {
+                       if (found > 0)
+                               strlcat(buf, ",", sizeof(buf));
+                       snprintf(tmp, sizeof(tmp), "%d", i);
+                       strlcat(buf, tmp, sizeof(buf));
+                       found++;
+               }
+       }
+
+       if (found == 0)
+               snprintf(buf, sizeof(buf), "<none>");
+
+       zlog_debug("%s: %s", __func__, buf);
+}
+
+static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea,
+                                  const struct thread *thread)
+{
+       static const char * const types[] = {
+               [THREAD_READ] = "read",
+               [THREAD_WRITE] = "write",
+               [THREAD_TIMER] = "timer",
+               [THREAD_EVENT] = "event",
+               [THREAD_READY] = "ready",
+               [THREAD_UNUSED] = "unused",
+               [THREAD_EXECUTE] = "exec",
+       };
+       ssize_t rv = 0;
+       char info[16] = "";
+
+       if (!thread)
+               return bputs(buf, "{(thread *)NULL}");
+
+       rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg);
+
+       if (thread->type < array_size(types) && types[thread->type])
+               rv += bprintfrr(buf, " %-6s", types[thread->type]);
+       else
+               rv += bprintfrr(buf, " INVALID(%u)", thread->type);
+
+       switch (thread->type) {
+       case THREAD_READ:
+       case THREAD_WRITE:
+               snprintfrr(info, sizeof(info), "fd=%d", thread->u.fd);
+               break;
+
+       case THREAD_TIMER:
+               snprintfrr(info, sizeof(info), "r=%pTVMud", &thread->u.sands);
+               break;
+       }
+
+       rv += bprintfrr(buf, " %-12s %s() %s from %s:%d}", info,
+                       thread->xref->funcname, thread->xref->dest,
+                       thread->xref->xref.file, thread->xref->xref.line);
+       return rv;
+}
+
+printfrr_ext_autoreg_p("TH", printfrr_thread);
+static ssize_t printfrr_thread(struct fbuf *buf, struct printfrr_eargs *ea,
+                              const void *ptr)
+{
+       const struct thread *thread = ptr;
+       struct timespec remain = {};
+
+       if (ea->fmt[0] == 'D') {
+               ea->fmt++;
+               return printfrr_thread_dbg(buf, ea, thread);
+       }
+
+       if (!thread) {
+               /* need to jump over time formatting flag characters in the
+                * input format string, i.e. adjust ea->fmt!
+                */
+               printfrr_time(buf, ea, &remain,
+                             TIMEFMT_TIMER_DEADLINE | TIMEFMT_SKIP);
+               return bputch(buf, '-');
+       }
+
+       TIMEVAL_TO_TIMESPEC(&thread->u.sands, &remain);
+       return printfrr_time(buf, ea, &remain, TIMEFMT_TIMER_DEADLINE);
+}
diff --git a/lib/event.h b/lib/event.h
new file mode 100644 (file)
index 0000000..128d11b
--- /dev/null
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Thread management routine header.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ */
+
+#ifndef _ZEBRA_THREAD_H
+#define _ZEBRA_THREAD_H
+
+#include <zebra.h>
+#include <pthread.h>
+#include <poll.h>
+#include "monotime.h"
+#include "frratomic.h"
+#include "typesafe.h"
+#include "xref.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool cputime_enabled;
+extern unsigned long cputime_threshold;
+/* capturing wallclock time is always enabled since it is fast (reading
+ * hardware TSC w/o syscalls)
+ */
+extern unsigned long walltime_threshold;
+
+struct rusage_t {
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+       struct timespec cpu;
+#else
+       struct rusage cpu;
+#endif
+       struct timeval real;
+};
+#define RUSAGE_T        struct rusage_t
+
+#define GETRUSAGE(X) thread_getrusage(X)
+
+PREDECL_LIST(thread_list);
+PREDECL_HEAP(thread_timer_list);
+
+struct fd_handler {
+       /* number of pfd that fit in the allocated space of pfds. This is a
+        * constant and is the same for both pfds and copy.
+        */
+       nfds_t pfdsize;
+
+       /* file descriptors to monitor for i/o */
+       struct pollfd *pfds;
+       /* number of pollfds stored in pfds */
+       nfds_t pfdcount;
+
+       /* chunk used for temp copy of pollfds */
+       struct pollfd *copy;
+       /* number of pollfds stored in copy */
+       nfds_t copycount;
+};
+
+struct xref_threadsched {
+       struct xref xref;
+
+       const char *funcname;
+       const char *dest;
+       uint32_t thread_type;
+};
+
+/* Master of the theads. */
+struct thread_master {
+       char *name;
+
+       struct thread **read;
+       struct thread **write;
+       struct thread_timer_list_head timer;
+       struct thread_list_head event, ready, unuse;
+       struct list *cancel_req;
+       bool canceled;
+       pthread_cond_t cancel_cond;
+       struct hash *cpu_record;
+       int io_pipe[2];
+       int fd_limit;
+       struct fd_handler handler;
+       unsigned long alloc;
+       long selectpoll_timeout;
+       bool spin;
+       bool handle_signals;
+       pthread_mutex_t mtx;
+       pthread_t owner;
+
+       bool ready_run_loop;
+       RUSAGE_T last_getrusage;
+};
+
+/* Thread itself. */
+struct thread {
+       uint8_t type;             /* thread type */
+       uint8_t add_type;         /* thread type */
+       struct thread_list_item threaditem;
+       struct thread_timer_list_item timeritem;
+       struct thread **ref;      /* external reference (if given) */
+       struct thread_master *master; /* pointer to the struct thread_master */
+       void (*func)(struct thread *); /* event function */
+       void *arg;                    /* event argument */
+       union {
+               int val;              /* second argument of the event. */
+               int fd;               /* file descriptor in case of r/w */
+               struct timeval sands; /* rest of time sands value. */
+       } u;
+       struct timeval real;
+       struct cpu_thread_history *hist; /* cache pointer to cpu_history */
+       unsigned long yield;             /* yield time in microseconds */
+       const struct xref_threadsched *xref;   /* origin location */
+       pthread_mutex_t mtx;   /* mutex for thread.c functions */
+       bool ignore_timer_late;
+};
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pTH" (struct thread *)
+#endif
+
+struct cpu_thread_history {
+       void (*func)(struct thread *);
+       atomic_size_t total_cpu_warn;
+       atomic_size_t total_wall_warn;
+       atomic_size_t total_starv_warn;
+       atomic_size_t total_calls;
+       atomic_size_t total_active;
+       struct time_stats {
+               atomic_size_t total, max;
+       } real;
+       struct time_stats cpu;
+       atomic_uint_fast32_t types;
+       const char *funcname;
+};
+
+/* Struct timeval's tv_usec one second value.  */
+#define TIMER_SECOND_MICRO 1000000L
+
+/* Thread types. */
+#define THREAD_READ           0
+#define THREAD_WRITE          1
+#define THREAD_TIMER          2
+#define THREAD_EVENT          3
+#define THREAD_READY          4
+#define THREAD_UNUSED         5
+#define THREAD_EXECUTE        6
+
+/* Thread yield time.  */
+#define THREAD_YIELD_TIME_SLOT     10 * 1000L /* 10ms */
+
+#define THREAD_TIMER_STRLEN 12
+
+/* Macros. */
+#define THREAD_ARG(X) ((X)->arg)
+#define THREAD_FD(X)  ((X)->u.fd)
+#define THREAD_VAL(X) ((X)->u.val)
+
+/*
+ * Please consider this macro deprecated, and do not use it in new code.
+ */
+#define THREAD_OFF(thread)                                             \
+       do {                                                           \
+               if ((thread))                                          \
+                       thread_cancel(&(thread));                      \
+       } while (0)
+
+/*
+ * Macro wrappers to generate xrefs for all thread add calls.  Includes
+ * file/line/function info for debugging/tracing.
+ */
+#include "lib/xref.h"
+
+#define _xref_t_a(addfn, type, m, f, a, v, t)                                  \
+       ({                                                                     \
+               static const struct xref_threadsched _xref                     \
+                               __attribute__((used)) = {                      \
+                       .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__),  \
+                       .funcname = #f,                                        \
+                       .dest = #t,                                            \
+                       .thread_type = THREAD_ ## type,                        \
+               };                                                             \
+               XREF_LINK(_xref.xref);                                         \
+               _thread_add_ ## addfn(&_xref, m, f, a, v, t);                  \
+       })                                                                     \
+       /* end */
+
+#define thread_add_read(m,f,a,v,t)       _xref_t_a(read_write, READ,  m,f,a,v,t)
+#define thread_add_write(m,f,a,v,t)      _xref_t_a(read_write, WRITE, m,f,a,v,t)
+#define thread_add_timer(m,f,a,v,t)      _xref_t_a(timer,      TIMER, m,f,a,v,t)
+#define thread_add_timer_msec(m,f,a,v,t) _xref_t_a(timer_msec, TIMER, m,f,a,v,t)
+#define thread_add_timer_tv(m,f,a,v,t)   _xref_t_a(timer_tv,   TIMER, m,f,a,v,t)
+#define thread_add_event(m,f,a,v,t)      _xref_t_a(event,      EVENT, m,f,a,v,t)
+
+#define thread_execute(m,f,a,v)                                                \
+       ({                                                                     \
+               static const struct xref_threadsched _xref                     \
+                               __attribute__((used)) = {                      \
+                       .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__),  \
+                       .funcname = #f,                                        \
+                       .dest = NULL,                                          \
+                       .thread_type = THREAD_EXECUTE,                         \
+               };                                                             \
+               XREF_LINK(_xref.xref);                                         \
+               _thread_execute(&_xref, m, f, a, v);                           \
+       }) /* end */
+
+/* Prototypes. */
+extern struct thread_master *thread_master_create(const char *);
+void thread_master_set_name(struct thread_master *master, const char *name);
+extern void thread_master_free(struct thread_master *);
+extern void thread_master_free_unused(struct thread_master *);
+
+extern void _thread_add_read_write(const struct xref_threadsched *xref,
+                                  struct thread_master *master,
+                                  void (*fn)(struct thread *), void *arg,
+                                  int fd, struct thread **tref);
+
+extern void _thread_add_timer(const struct xref_threadsched *xref,
+                             struct thread_master *master,
+                             void (*fn)(struct thread *), void *arg, long t,
+                             struct thread **tref);
+
+extern void _thread_add_timer_msec(const struct xref_threadsched *xref,
+                                  struct thread_master *master,
+                                  void (*fn)(struct thread *), void *arg,
+                                  long t, struct thread **tref);
+
+extern void _thread_add_timer_tv(const struct xref_threadsched *xref,
+                                struct thread_master *master,
+                                void (*fn)(struct thread *), void *arg,
+                                struct timeval *tv, struct thread **tref);
+
+extern void _thread_add_event(const struct xref_threadsched *xref,
+                             struct thread_master *master,
+                             void (*fn)(struct thread *), void *arg, int val,
+                             struct thread **tref);
+
+extern void _thread_execute(const struct xref_threadsched *xref,
+                           struct thread_master *master,
+                           void (*fn)(struct thread *), void *arg, int val);
+
+extern void thread_cancel(struct thread **event);
+extern void thread_cancel_async(struct thread_master *, struct thread **,
+                               void *);
+/* Cancel ready tasks with an arg matching 'arg' */
+extern void thread_cancel_event_ready(struct thread_master *m, void *arg);
+/* Cancel all tasks with an arg matching 'arg', including timers and io */
+extern void thread_cancel_event(struct thread_master *m, void *arg);
+extern struct thread *thread_fetch(struct thread_master *, struct thread *);
+extern void thread_call(struct thread *);
+extern unsigned long thread_timer_remain_second(struct thread *);
+extern struct timeval thread_timer_remain(struct thread *);
+extern unsigned long thread_timer_remain_msec(struct thread *);
+extern int thread_should_yield(struct thread *);
+/* set yield time for thread */
+extern void thread_set_yield_time(struct thread *, unsigned long);
+
+/* Internal libfrr exports */
+extern void thread_getrusage(RUSAGE_T *);
+extern void thread_cmd_init(void);
+
+/* Returns elapsed real (wall clock) time. */
+extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
+                                         unsigned long *cpu_time_elapsed);
+
+/* only for use in logging functions! */
+extern pthread_key_t thread_current;
+extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
+               struct thread *t_timer);
+
+static inline bool thread_is_scheduled(struct thread *thread)
+{
+       if (thread)
+               return true;
+
+       return false;
+}
+
+/* Debug signal mask */
+void debug_signals(const sigset_t *sigs);
+
+static inline void thread_ignore_late_timer(struct thread *thread)
+{
+       thread->ignore_timer_late = true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_THREAD_H */
index b1d08717fbed236a73ca5bece52b143942642de7..c14ba779229201bfaed0fb8200be9eee42cca84f 100644 (file)
@@ -11,7 +11,7 @@
 #include "frratomic.h"
 #include "memory.h"
 #include "frrcu.h"
-#include "thread.h"
+#include "event.h"
 
 #ifdef __cplusplus
 extern "C" {
index 2673d576052eeb2982edfa42f03bceef3a487d67..525e49942cc5fb13ad076a68f5dcb6e777d72696 100644 (file)
@@ -15,7 +15,7 @@
 #include <zebra.h>
 #include <zmq.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "frr_zmq.h"
 #include "log.h"
index f12291d60210f1030f63b2d2e6c98cec36922bf6..bfc1e93b16392f39317378b1aa77c030f778ce84 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _FRRZMQ_H
 #define _FRRZMQ_H
 
-#include "thread.h"
+#include "event.h"
 #include <zmq.h>
 
 #ifdef __cplusplus
index b01cf87287d26b8bfb80562c05d5c691a47c2404..3ecbfcabf9889927ecc943e91dc57cabe9535435 100644 (file)
@@ -10,7 +10,7 @@
 #include "memory.h"
 #include "prefix.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "zclient.h"
 #include "table.h"
index 97e9b93c101e45f776111432a237235a542967a2..3657346507f514f9d0172ac6c0bb8a607824c358 100644 (file)
@@ -11,7 +11,7 @@
 #include "typesafe.h"
 #include "sigevent.h"
 #include "privs.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "getopt.h"
 #include "module.h"
index 92c469706a5c15396b206a52c7c1731448b0296e..d13cdc20b13be51708017b358da8085ec035a908 100644 (file)
@@ -21,7 +21,7 @@
 #include <lttng/tracepoint.h>
 
 #include "hash.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "table.h"
index ac29b8f27ceaa8ab3e05d1978f0900539a956986..10712964bdcfd6e866b7c0433b1d0062528c214e 100644 (file)
@@ -13,7 +13,7 @@ extern "C" {
 #endif
 
 #include "mgmt_pb.h"
-#include "thread.h"
+#include "event.h"
 #include "mgmtd/mgmt_defines.h"
 
 /***************************************************************
index 2fab03bc5472b39bc7a8a77f4f4cb86194ca1b32..e7564f2688aebf70600ed79ece3e90460c388ca4 100644 (file)
@@ -10,7 +10,7 @@
 #include "network.h"
 #include "sockopt.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "mgmt_msg.h"
 
 
index 854875170b924a5597075c9b2d355a953e3fbb7e..90dab8da76303171314de11d9ff8110031f93ac2 100644 (file)
@@ -8,7 +8,7 @@
 #define _MGMT_MSG_H
 
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 
 #define MGMT_MSG_MARKER (0x4D724B21u) /* ASCII - "MrK!"*/
 
index 4b5028c87e24d80eff95c546cc550597bbd24d87..6820a59cc6e2b13a10c094b0e9075e3ab7b9a8d5 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _FRR_NORTHBOUND_H_
 #define _FRR_NORTHBOUND_H_
 
-#include "thread.h"
+#include "event.h"
 #include "hook.h"
 #include "linklist.h"
 #include "openbsd-tree.h"
index 274a0ca45a0deb6fb533a54a12375a6da8a6dea9..d68e22368c8537395e572d30ed3fce01586b9436 100644 (file)
@@ -12,7 +12,7 @@
 #include "log.h"
 #include "libfrr.h"
 #include "lib/version.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "command.h"
 #include "lib_errors.h"
 #include "northbound.h"
index 77ecf855b404d7ecdd9c5b4eff7262ac6756a562..8a028b909695e88386563b8bc2992b2727ca9f97 100644 (file)
@@ -10,7 +10,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 
 #ifdef __cplusplus
index 09b156ba390d0976665f040f527a02083d8fc44a..6ebdcbf9cb4424e8aa5dec5b13bacf8d3ece3583 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "hash.h"
 #include "log.h"
index 2918576c03a779537eb87347effbec4e4b210c82..ffc84e5fe85dbd2f4e0b1275a6e0a7b873399f39 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "typesafe.h"
 #include "jhash.h"
-#include "thread.h"
+#include "event.h"
 #include "lib_errors.h"
 #include "resolver.h"
 #include "command.h"
index d3f38f742de9806e8f06e50060c29344402817ec..764e3e72aeee0aeb606cf23214d4c57aaf5b665a 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef _FRR_RESOLVER_H
 #define _FRR_RESOLVER_H
 
-#include "thread.h"
+#include "event.h"
 #include "sockunion.h"
 
 #ifdef __cplusplus
index e58b9a70c02b8fa359e316ac9015fbe20ee378a0..69b3f54aa73b4fc29e51df932a77fa0eeeb762d7 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef _FRR_SIGNAL_H
 #define _FRR_SIGNAL_H
 
-#include <thread.h>
+#include <event.h>
 
 #ifdef __cplusplus
 extern "C" {
index 28a303cf729c3a78dc19aaf34e9b6704d98f9b98..dd1689f7316098f20e3a8677cf1cebe1a6e2f0cc 100644 (file)
@@ -9,7 +9,7 @@
 #include <net-snmp/agent/net-snmp-agent-includes.h>
 #include <net-snmp/agent/snmp_vars.h>
 
-#include "thread.h"
+#include "event.h"
 #include "hook.h"
 
 #ifdef __cplusplus
index 1e80b5ec2debdd785f057e44d411670b0a367a52..36b059a990eea5ba6f95c5ac58c63f8db07ffdc1 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "command.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 
 DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff");
index d456629bbd9a97907aa4489a642031174ec928a2..9f2f4033fcd56e47492cad03862557312331a468 100644 (file)
@@ -108,7 +108,7 @@ lib_libfrr_la_SOURCES = \
        lib/systemd.c \
        lib/table.c \
        lib/termtable.c \
-       lib/thread.c \
+       lib/event.c \
        lib/typerb.c \
        lib/typesafe.c \
        lib/vector.c \
@@ -181,7 +181,7 @@ clippy_scan += \
        lib/plist.c \
        lib/routemap.c \
        lib/routemap_cli.c \
-       lib/thread.c \
+       lib/event.c \
        lib/vty.c \
        lib/zlog_5424_cli.c \
        # end
@@ -288,7 +288,7 @@ pkginclude_HEADERS += \
        lib/systemd.h \
        lib/table.h \
        lib/termtable.h \
-       lib/thread.h \
+       lib/event.h \
        lib/trace.h \
        lib/typerb.h \
        lib/typesafe.h \
index 0106e88b93c082cef7a5a6e5c8e5ad8e3b129048..458bea5144e7ce4dd7992f7c5afad362746070ca 100644 (file)
@@ -7,7 +7,7 @@
 #include <zebra.h>
 #include <sys/un.h>
 
-#include "thread.h"
+#include "event.h"
 #include "systemd.h"
 #include "lib_errors.h"
 
diff --git a/lib/thread.c b/lib/thread.c
deleted file mode 100644 (file)
index 87ad3d8..0000000
+++ /dev/null
@@ -1,2198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* Thread management routine
- * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
- */
-
-/* #define DEBUG */
-
-#include <zebra.h>
-#include <sys/resource.h>
-
-#include "thread.h"
-#include "memory.h"
-#include "frrcu.h"
-#include "log.h"
-#include "hash.h"
-#include "command.h"
-#include "sigevent.h"
-#include "network.h"
-#include "jhash.h"
-#include "frratomic.h"
-#include "frr_pthread.h"
-#include "lib_errors.h"
-#include "libfrr_trace.h"
-#include "libfrr.h"
-
-DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread");
-DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master");
-DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info");
-DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats");
-
-DECLARE_LIST(thread_list, struct thread, threaditem);
-
-struct cancel_req {
-       int flags;
-       struct thread *thread;
-       void *eventobj;
-       struct thread **threadref;
-};
-
-/* Flags for task cancellation */
-#define THREAD_CANCEL_FLAG_READY     0x01
-
-static int thread_timer_cmp(const struct thread *a, const struct thread *b)
-{
-       if (a->u.sands.tv_sec < b->u.sands.tv_sec)
-               return -1;
-       if (a->u.sands.tv_sec > b->u.sands.tv_sec)
-               return 1;
-       if (a->u.sands.tv_usec < b->u.sands.tv_usec)
-               return -1;
-       if (a->u.sands.tv_usec > b->u.sands.tv_usec)
-               return 1;
-       return 0;
-}
-
-DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp);
-
-#if defined(__APPLE__)
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-#endif
-
-#define AWAKEN(m)                                                              \
-       do {                                                                   \
-               const unsigned char wakebyte = 0x01;                           \
-               write(m->io_pipe[1], &wakebyte, 1);                            \
-       } while (0);
-
-/* control variable for initializer */
-static pthread_once_t init_once = PTHREAD_ONCE_INIT;
-pthread_key_t thread_current;
-
-static pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
-static struct list *masters;
-
-static void thread_free(struct thread_master *master, struct thread *thread);
-
-#ifndef EXCLUDE_CPU_TIME
-#define EXCLUDE_CPU_TIME 0
-#endif
-#ifndef CONSUMED_TIME_CHECK
-#define CONSUMED_TIME_CHECK 0
-#endif
-
-bool cputime_enabled = !EXCLUDE_CPU_TIME;
-unsigned long cputime_threshold = CONSUMED_TIME_CHECK;
-unsigned long walltime_threshold = CONSUMED_TIME_CHECK;
-
-/* CLI start ---------------------------------------------------------------- */
-#include "lib/thread_clippy.c"
-
-static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
-{
-       int size = sizeof(a->func);
-
-       return jhash(&a->func, size, 0);
-}
-
-static bool cpu_record_hash_cmp(const struct cpu_thread_history *a,
-                              const struct cpu_thread_history *b)
-{
-       return a->func == b->func;
-}
-
-static void *cpu_record_hash_alloc(struct cpu_thread_history *a)
-{
-       struct cpu_thread_history *new;
-       new = XCALLOC(MTYPE_THREAD_STATS, sizeof(struct cpu_thread_history));
-       new->func = a->func;
-       new->funcname = a->funcname;
-       return new;
-}
-
-static void cpu_record_hash_free(void *a)
-{
-       struct cpu_thread_history *hist = a;
-
-       XFREE(MTYPE_THREAD_STATS, hist);
-}
-
-static void vty_out_cpu_thread_history(struct vty *vty,
-                                      struct cpu_thread_history *a)
-{
-       vty_out(vty,
-               "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu %10zu",
-               a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
-               a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
-               (a->real.total / a->total_calls), a->real.max,
-               a->total_cpu_warn, a->total_wall_warn, a->total_starv_warn);
-       vty_out(vty, "  %c%c%c%c%c  %s\n",
-               a->types & (1 << THREAD_READ) ? 'R' : ' ',
-               a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
-               a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
-               a->types & (1 << THREAD_EVENT) ? 'E' : ' ',
-               a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname);
-}
-
-static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[])
-{
-       struct cpu_thread_history *totals = args[0];
-       struct cpu_thread_history copy;
-       struct vty *vty = args[1];
-       uint8_t *filter = args[2];
-
-       struct cpu_thread_history *a = bucket->data;
-
-       copy.total_active =
-               atomic_load_explicit(&a->total_active, memory_order_seq_cst);
-       copy.total_calls =
-               atomic_load_explicit(&a->total_calls, memory_order_seq_cst);
-       copy.total_cpu_warn =
-               atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst);
-       copy.total_wall_warn =
-               atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst);
-       copy.total_starv_warn = atomic_load_explicit(&a->total_starv_warn,
-                                                    memory_order_seq_cst);
-       copy.cpu.total =
-               atomic_load_explicit(&a->cpu.total, memory_order_seq_cst);
-       copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst);
-       copy.real.total =
-               atomic_load_explicit(&a->real.total, memory_order_seq_cst);
-       copy.real.max =
-               atomic_load_explicit(&a->real.max, memory_order_seq_cst);
-       copy.types = atomic_load_explicit(&a->types, memory_order_seq_cst);
-       copy.funcname = a->funcname;
-
-       if (!(copy.types & *filter))
-               return;
-
-       vty_out_cpu_thread_history(vty, &copy);
-       totals->total_active += copy.total_active;
-       totals->total_calls += copy.total_calls;
-       totals->total_cpu_warn += copy.total_cpu_warn;
-       totals->total_wall_warn += copy.total_wall_warn;
-       totals->total_starv_warn += copy.total_starv_warn;
-       totals->real.total += copy.real.total;
-       if (totals->real.max < copy.real.max)
-               totals->real.max = copy.real.max;
-       totals->cpu.total += copy.cpu.total;
-       if (totals->cpu.max < copy.cpu.max)
-               totals->cpu.max = copy.cpu.max;
-}
-
-static void cpu_record_print(struct vty *vty, uint8_t filter)
-{
-       struct cpu_thread_history tmp;
-       void *args[3] = {&tmp, vty, &filter};
-       struct thread_master *m;
-       struct listnode *ln;
-
-       if (!cputime_enabled)
-               vty_out(vty,
-                       "\n"
-                       "Collecting CPU time statistics is currently disabled.  Following statistics\n"
-                       "will be zero or may display data from when collection was enabled.  Use the\n"
-                       "  \"service cputime-stats\"  command to start collecting data.\n"
-                       "\nCounters and wallclock times are always maintained and should be accurate.\n");
-
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.funcname = "TOTAL";
-       tmp.types = filter;
-
-       frr_with_mutex (&masters_mtx) {
-               for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
-                       const char *name = m->name ? m->name : "main";
-
-                       char underline[strlen(name) + 1];
-                       memset(underline, '-', sizeof(underline));
-                       underline[sizeof(underline) - 1] = '\0';
-
-                       vty_out(vty, "\n");
-                       vty_out(vty, "Showing statistics for pthread %s\n",
-                               name);
-                       vty_out(vty, "-------------------------------%s\n",
-                               underline);
-                       vty_out(vty, "%30s %18s %18s\n", "",
-                               "CPU (user+system):", "Real (wall-clock):");
-                       vty_out(vty,
-                               "Active   Runtime(ms)   Invoked Avg uSec Max uSecs");
-                       vty_out(vty, " Avg uSec Max uSecs");
-                       vty_out(vty,
-                               "  CPU_Warn Wall_Warn Starv_Warn Type   Thread\n");
-
-                       if (m->cpu_record->count)
-                               hash_iterate(
-                                       m->cpu_record,
-                                       (void (*)(struct hash_bucket *,
-                                                 void *))cpu_record_hash_print,
-                                       args);
-                       else
-                               vty_out(vty, "No data to display yet.\n");
-
-                       vty_out(vty, "\n");
-               }
-       }
-
-       vty_out(vty, "\n");
-       vty_out(vty, "Total thread statistics\n");
-       vty_out(vty, "-------------------------\n");
-       vty_out(vty, "%30s %18s %18s\n", "",
-               "CPU (user+system):", "Real (wall-clock):");
-       vty_out(vty, "Active   Runtime(ms)   Invoked Avg uSec Max uSecs");
-       vty_out(vty, " Avg uSec Max uSecs  CPU_Warn Wall_Warn");
-       vty_out(vty, "  Type  Thread\n");
-
-       if (tmp.total_calls > 0)
-               vty_out_cpu_thread_history(vty, &tmp);
-}
-
-static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[])
-{
-       uint8_t *filter = args[0];
-       struct hash *cpu_record = args[1];
-
-       struct cpu_thread_history *a = bucket->data;
-
-       if (!(a->types & *filter))
-               return;
-
-       hash_release(cpu_record, bucket->data);
-}
-
-static void cpu_record_clear(uint8_t filter)
-{
-       uint8_t *tmp = &filter;
-       struct thread_master *m;
-       struct listnode *ln;
-
-       frr_with_mutex (&masters_mtx) {
-               for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
-                       frr_with_mutex (&m->mtx) {
-                               void *args[2] = {tmp, m->cpu_record};
-                               hash_iterate(
-                                       m->cpu_record,
-                                       (void (*)(struct hash_bucket *,
-                                                 void *))cpu_record_hash_clear,
-                                       args);
-                       }
-               }
-       }
-}
-
-static uint8_t parse_filter(const char *filterstr)
-{
-       int i = 0;
-       int filter = 0;
-
-       while (filterstr[i] != '\0') {
-               switch (filterstr[i]) {
-               case 'r':
-               case 'R':
-                       filter |= (1 << THREAD_READ);
-                       break;
-               case 'w':
-               case 'W':
-                       filter |= (1 << THREAD_WRITE);
-                       break;
-               case 't':
-               case 'T':
-                       filter |= (1 << THREAD_TIMER);
-                       break;
-               case 'e':
-               case 'E':
-                       filter |= (1 << THREAD_EVENT);
-                       break;
-               case 'x':
-               case 'X':
-                       filter |= (1 << THREAD_EXECUTE);
-                       break;
-               default:
-                       break;
-               }
-               ++i;
-       }
-       return filter;
-}
-
-DEFUN_NOSH (show_thread_cpu,
-           show_thread_cpu_cmd,
-           "show thread cpu [FILTER]",
-           SHOW_STR
-           "Thread information\n"
-           "Thread CPU usage\n"
-           "Display filter (rwtex)\n")
-{
-       uint8_t filter = (uint8_t)-1U;
-       int idx = 0;
-
-       if (argv_find(argv, argc, "FILTER", &idx)) {
-               filter = parse_filter(argv[idx]->arg);
-               if (!filter) {
-                       vty_out(vty,
-                               "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
-                               argv[idx]->arg);
-                       return CMD_WARNING;
-               }
-       }
-
-       cpu_record_print(vty, filter);
-       return CMD_SUCCESS;
-}
-
-DEFPY (service_cputime_stats,
-       service_cputime_stats_cmd,
-       "[no] service cputime-stats",
-       NO_STR
-       "Set up miscellaneous service\n"
-       "Collect CPU usage statistics\n")
-{
-       cputime_enabled = !no;
-       return CMD_SUCCESS;
-}
-
-DEFPY (service_cputime_warning,
-       service_cputime_warning_cmd,
-       "[no] service cputime-warning (1-4294967295)",
-       NO_STR
-       "Set up miscellaneous service\n"
-       "Warn for tasks exceeding CPU usage threshold\n"
-       "Warning threshold in milliseconds\n")
-{
-       if (no)
-               cputime_threshold = 0;
-       else
-               cputime_threshold = cputime_warning * 1000;
-       return CMD_SUCCESS;
-}
-
-ALIAS (service_cputime_warning,
-       no_service_cputime_warning_cmd,
-       "no service cputime-warning",
-       NO_STR
-       "Set up miscellaneous service\n"
-       "Warn for tasks exceeding CPU usage threshold\n")
-
-DEFPY (service_walltime_warning,
-       service_walltime_warning_cmd,
-       "[no] service walltime-warning (1-4294967295)",
-       NO_STR
-       "Set up miscellaneous service\n"
-       "Warn for tasks exceeding total wallclock threshold\n"
-       "Warning threshold in milliseconds\n")
-{
-       if (no)
-               walltime_threshold = 0;
-       else
-               walltime_threshold = walltime_warning * 1000;
-       return CMD_SUCCESS;
-}
-
-ALIAS (service_walltime_warning,
-       no_service_walltime_warning_cmd,
-       "no service walltime-warning",
-       NO_STR
-       "Set up miscellaneous service\n"
-       "Warn for tasks exceeding total wallclock threshold\n")
-
-static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
-{
-       const char *name = m->name ? m->name : "main";
-       char underline[strlen(name) + 1];
-       struct thread *thread;
-       uint32_t i;
-
-       memset(underline, '-', sizeof(underline));
-       underline[sizeof(underline) - 1] = '\0';
-
-       vty_out(vty, "\nShowing poll FD's for %s\n", name);
-       vty_out(vty, "----------------------%s\n", underline);
-       vty_out(vty, "Count: %u/%d\n", (uint32_t)m->handler.pfdcount,
-               m->fd_limit);
-       for (i = 0; i < m->handler.pfdcount; i++) {
-               vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\t\t", i,
-                       m->handler.pfds[i].fd, m->handler.pfds[i].events,
-                       m->handler.pfds[i].revents);
-
-               if (m->handler.pfds[i].events & POLLIN) {
-                       thread = m->read[m->handler.pfds[i].fd];
-
-                       if (!thread)
-                               vty_out(vty, "ERROR ");
-                       else
-                               vty_out(vty, "%s ", thread->xref->funcname);
-               } else
-                       vty_out(vty, " ");
-
-               if (m->handler.pfds[i].events & POLLOUT) {
-                       thread = m->write[m->handler.pfds[i].fd];
-
-                       if (!thread)
-                               vty_out(vty, "ERROR\n");
-                       else
-                               vty_out(vty, "%s\n", thread->xref->funcname);
-               } else
-                       vty_out(vty, "\n");
-       }
-}
-
-DEFUN_NOSH (show_thread_poll,
-           show_thread_poll_cmd,
-           "show thread poll",
-           SHOW_STR
-           "Thread information\n"
-           "Show poll FD's and information\n")
-{
-       struct listnode *node;
-       struct thread_master *m;
-
-       frr_with_mutex (&masters_mtx) {
-               for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
-                       show_thread_poll_helper(vty, m);
-               }
-       }
-
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (clear_thread_cpu,
-       clear_thread_cpu_cmd,
-       "clear thread cpu [FILTER]",
-       "Clear stored data in all pthreads\n"
-       "Thread information\n"
-       "Thread CPU usage\n"
-       "Display filter (rwtexb)\n")
-{
-       uint8_t filter = (uint8_t)-1U;
-       int idx = 0;
-
-       if (argv_find(argv, argc, "FILTER", &idx)) {
-               filter = parse_filter(argv[idx]->arg);
-               if (!filter) {
-                       vty_out(vty,
-                               "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
-                               argv[idx]->arg);
-                       return CMD_WARNING;
-               }
-       }
-
-       cpu_record_clear(filter);
-       return CMD_SUCCESS;
-}
-
-static void show_thread_timers_helper(struct vty *vty, struct thread_master *m)
-{
-       const char *name = m->name ? m->name : "main";
-       char underline[strlen(name) + 1];
-       struct thread *thread;
-
-       memset(underline, '-', sizeof(underline));
-       underline[sizeof(underline) - 1] = '\0';
-
-       vty_out(vty, "\nShowing timers for %s\n", name);
-       vty_out(vty, "-------------------%s\n", underline);
-
-       frr_each (thread_timer_list, &m->timer, thread) {
-               vty_out(vty, "  %-50s%pTH\n", thread->hist->funcname, thread);
-       }
-}
-
-DEFPY_NOSH (show_thread_timers,
-           show_thread_timers_cmd,
-           "show thread timers",
-           SHOW_STR
-           "Thread information\n"
-           "Show all timers and how long they have in the system\n")
-{
-       struct listnode *node;
-       struct thread_master *m;
-
-       frr_with_mutex (&masters_mtx) {
-               for (ALL_LIST_ELEMENTS_RO(masters, node, m))
-                       show_thread_timers_helper(vty, m);
-       }
-
-       return CMD_SUCCESS;
-}
-
-void thread_cmd_init(void)
-{
-       install_element(VIEW_NODE, &show_thread_cpu_cmd);
-       install_element(VIEW_NODE, &show_thread_poll_cmd);
-       install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
-
-       install_element(CONFIG_NODE, &service_cputime_stats_cmd);
-       install_element(CONFIG_NODE, &service_cputime_warning_cmd);
-       install_element(CONFIG_NODE, &no_service_cputime_warning_cmd);
-       install_element(CONFIG_NODE, &service_walltime_warning_cmd);
-       install_element(CONFIG_NODE, &no_service_walltime_warning_cmd);
-
-       install_element(VIEW_NODE, &show_thread_timers_cmd);
-}
-/* CLI end ------------------------------------------------------------------ */
-
-
-static void cancelreq_del(void *cr)
-{
-       XFREE(MTYPE_TMP, cr);
-}
-
-/* initializer, only ever called once */
-static void initializer(void)
-{
-       pthread_key_create(&thread_current, NULL);
-}
-
-struct thread_master *thread_master_create(const char *name)
-{
-       struct thread_master *rv;
-       struct rlimit limit;
-
-       pthread_once(&init_once, &initializer);
-
-       rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
-
-       /* Initialize master mutex */
-       pthread_mutex_init(&rv->mtx, NULL);
-       pthread_cond_init(&rv->cancel_cond, NULL);
-
-       /* Set name */
-       name = name ? name : "default";
-       rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
-
-       /* Initialize I/O task data structures */
-
-       /* Use configured limit if present, ulimit otherwise. */
-       rv->fd_limit = frr_get_fd_limit();
-       if (rv->fd_limit == 0) {
-               getrlimit(RLIMIT_NOFILE, &limit);
-               rv->fd_limit = (int)limit.rlim_cur;
-       }
-
-       rv->read = XCALLOC(MTYPE_THREAD_POLL,
-                          sizeof(struct thread *) * rv->fd_limit);
-
-       rv->write = XCALLOC(MTYPE_THREAD_POLL,
-                           sizeof(struct thread *) * rv->fd_limit);
-
-       char tmhashname[strlen(name) + 32];
-       snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash",
-                name);
-       rv->cpu_record = hash_create_size(
-               8, (unsigned int (*)(const void *))cpu_record_hash_key,
-               (bool (*)(const void *, const void *))cpu_record_hash_cmp,
-               tmhashname);
-
-       thread_list_init(&rv->event);
-       thread_list_init(&rv->ready);
-       thread_list_init(&rv->unuse);
-       thread_timer_list_init(&rv->timer);
-
-       /* Initialize thread_fetch() settings */
-       rv->spin = true;
-       rv->handle_signals = true;
-
-       /* Set pthread owner, should be updated by actual owner */
-       rv->owner = pthread_self();
-       rv->cancel_req = list_new();
-       rv->cancel_req->del = cancelreq_del;
-       rv->canceled = true;
-
-       /* Initialize pipe poker */
-       pipe(rv->io_pipe);
-       set_nonblocking(rv->io_pipe[0]);
-       set_nonblocking(rv->io_pipe[1]);
-
-       /* Initialize data structures for poll() */
-       rv->handler.pfdsize = rv->fd_limit;
-       rv->handler.pfdcount = 0;
-       rv->handler.pfds = XCALLOC(MTYPE_THREAD_MASTER,
-                                  sizeof(struct pollfd) * rv->handler.pfdsize);
-       rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER,
-                                  sizeof(struct pollfd) * rv->handler.pfdsize);
-
-       /* add to list of threadmasters */
-       frr_with_mutex (&masters_mtx) {
-               if (!masters)
-                       masters = list_new();
-
-               listnode_add(masters, rv);
-       }
-
-       return rv;
-}
-
-void thread_master_set_name(struct thread_master *master, const char *name)
-{
-       frr_with_mutex (&master->mtx) {
-               XFREE(MTYPE_THREAD_MASTER, master->name);
-               master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
-       }
-}
-
-#define THREAD_UNUSED_DEPTH 10
-
-/* Move thread to unuse list. */
-static void thread_add_unuse(struct thread_master *m, struct thread *thread)
-{
-       pthread_mutex_t mtxc = thread->mtx;
-
-       assert(m != NULL && thread != NULL);
-
-       thread->hist->total_active--;
-       memset(thread, 0, sizeof(struct thread));
-       thread->type = THREAD_UNUSED;
-
-       /* Restore the thread mutex context. */
-       thread->mtx = mtxc;
-
-       if (thread_list_count(&m->unuse) < THREAD_UNUSED_DEPTH) {
-               thread_list_add_tail(&m->unuse, thread);
-               return;
-       }
-
-       thread_free(m, thread);
-}
-
-/* Free all unused thread. */
-static void thread_list_free(struct thread_master *m,
-               struct thread_list_head *list)
-{
-       struct thread *t;
-
-       while ((t = thread_list_pop(list)))
-               thread_free(m, t);
-}
-
-static void thread_array_free(struct thread_master *m,
-                             struct thread **thread_array)
-{
-       struct thread *t;
-       int index;
-
-       for (index = 0; index < m->fd_limit; ++index) {
-               t = thread_array[index];
-               if (t) {
-                       thread_array[index] = NULL;
-                       thread_free(m, t);
-               }
-       }
-       XFREE(MTYPE_THREAD_POLL, thread_array);
-}
-
-/*
- * thread_master_free_unused
- *
- * As threads are finished with they are put on the
- * unuse list for later reuse.
- * If we are shutting down, Free up unused threads
- * So we can see if we forget to shut anything off
- */
-void thread_master_free_unused(struct thread_master *m)
-{
-       frr_with_mutex (&m->mtx) {
-               struct thread *t;
-               while ((t = thread_list_pop(&m->unuse)))
-                       thread_free(m, t);
-       }
-}
-
-/* Stop thread scheduler. */
-void thread_master_free(struct thread_master *m)
-{
-       struct thread *t;
-
-       frr_with_mutex (&masters_mtx) {
-               listnode_delete(masters, m);
-               if (masters->count == 0) {
-                       list_delete(&masters);
-               }
-       }
-
-       thread_array_free(m, m->read);
-       thread_array_free(m, m->write);
-       while ((t = thread_timer_list_pop(&m->timer)))
-               thread_free(m, t);
-       thread_list_free(m, &m->event);
-       thread_list_free(m, &m->ready);
-       thread_list_free(m, &m->unuse);
-       pthread_mutex_destroy(&m->mtx);
-       pthread_cond_destroy(&m->cancel_cond);
-       close(m->io_pipe[0]);
-       close(m->io_pipe[1]);
-       list_delete(&m->cancel_req);
-       m->cancel_req = NULL;
-
-       hash_clean_and_free(&m->cpu_record, cpu_record_hash_free);
-
-       XFREE(MTYPE_THREAD_MASTER, m->name);
-       XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
-       XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
-       XFREE(MTYPE_THREAD_MASTER, m);
-}
-
-/* Return remain time in milliseconds. */
-unsigned long thread_timer_remain_msec(struct thread *thread)
-{
-       int64_t remain;
-
-       if (!thread_is_scheduled(thread))
-               return 0;
-
-       frr_with_mutex (&thread->mtx) {
-               remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
-       }
-
-       return remain < 0 ? 0 : remain;
-}
-
-/* Return remain time in seconds. */
-unsigned long thread_timer_remain_second(struct thread *thread)
-{
-       return thread_timer_remain_msec(thread) / 1000LL;
-}
-
-struct timeval thread_timer_remain(struct thread *thread)
-{
-       struct timeval remain;
-       frr_with_mutex (&thread->mtx) {
-               monotime_until(&thread->u.sands, &remain);
-       }
-       return remain;
-}
-
-static int time_hhmmss(char *buf, int buf_size, long sec)
-{
-       long hh;
-       long mm;
-       int wr;
-
-       assert(buf_size >= 8);
-
-       hh = sec / 3600;
-       sec %= 3600;
-       mm = sec / 60;
-       sec %= 60;
-
-       wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec);
-
-       return wr != 8;
-}
-
-char *thread_timer_to_hhmmss(char *buf, int buf_size,
-               struct thread *t_timer)
-{
-       if (t_timer) {
-               time_hhmmss(buf, buf_size,
-                               thread_timer_remain_second(t_timer));
-       } else {
-               snprintf(buf, buf_size, "--:--:--");
-       }
-       return buf;
-}
-
-/* Get new thread.  */
-static struct thread *thread_get(struct thread_master *m, uint8_t type,
-                                void (*func)(struct thread *), void *arg,
-                                const struct xref_threadsched *xref)
-{
-       struct thread *thread = thread_list_pop(&m->unuse);
-       struct cpu_thread_history tmp;
-
-       if (!thread) {
-               thread = XCALLOC(MTYPE_THREAD, sizeof(struct thread));
-               /* mutex only needs to be initialized at struct creation. */
-               pthread_mutex_init(&thread->mtx, NULL);
-               m->alloc++;
-       }
-
-       thread->type = type;
-       thread->add_type = type;
-       thread->master = m;
-       thread->arg = arg;
-       thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
-       thread->ref = NULL;
-       thread->ignore_timer_late = false;
-
-       /*
-        * So if the passed in funcname is not what we have
-        * stored that means the thread->hist needs to be
-        * updated.  We keep the last one around in unused
-        * under the assumption that we are probably
-        * going to immediately allocate the same
-        * type of thread.
-        * This hopefully saves us some serious
-        * hash_get lookups.
-        */
-       if ((thread->xref && thread->xref->funcname != xref->funcname)
-           || thread->func != func) {
-               tmp.func = func;
-               tmp.funcname = xref->funcname;
-               thread->hist =
-                       hash_get(m->cpu_record, &tmp,
-                                (void *(*)(void *))cpu_record_hash_alloc);
-       }
-       thread->hist->total_active++;
-       thread->func = func;
-       thread->xref = xref;
-
-       return thread;
-}
-
-static void thread_free(struct thread_master *master, struct thread *thread)
-{
-       /* Update statistics. */
-       assert(master->alloc > 0);
-       master->alloc--;
-
-       /* Free allocated resources. */
-       pthread_mutex_destroy(&thread->mtx);
-       XFREE(MTYPE_THREAD, thread);
-}
-
-static int fd_poll(struct thread_master *m, const struct timeval *timer_wait,
-                  bool *eintr_p)
-{
-       sigset_t origsigs;
-       unsigned char trash[64];
-       nfds_t count = m->handler.copycount;
-
-       /*
-        * If timer_wait is null here, that means poll() should block
-        * indefinitely, unless the thread_master has overridden it by setting
-        * ->selectpoll_timeout.
-        *
-        * If the value is positive, it specifies the maximum number of
-        * milliseconds to wait. If the timeout is -1, it specifies that
-        * we should never wait and always return immediately even if no
-        * event is detected. If the value is zero, the behavior is default.
-        */
-       int timeout = -1;
-
-       /* number of file descriptors with events */
-       int num;
-
-       if (timer_wait != NULL
-           && m->selectpoll_timeout == 0) // use the default value
-               timeout = (timer_wait->tv_sec * 1000)
-                         + (timer_wait->tv_usec / 1000);
-       else if (m->selectpoll_timeout > 0) // use the user's timeout
-               timeout = m->selectpoll_timeout;
-       else if (m->selectpoll_timeout
-                < 0) // effect a poll (return immediately)
-               timeout = 0;
-
-       zlog_tls_buffer_flush();
-       rcu_read_unlock();
-       rcu_assert_read_unlocked();
-
-       /* add poll pipe poker */
-       assert(count + 1 < m->handler.pfdsize);
-       m->handler.copy[count].fd = m->io_pipe[0];
-       m->handler.copy[count].events = POLLIN;
-       m->handler.copy[count].revents = 0x00;
-
-       /* We need to deal with a signal-handling race here: we
-        * don't want to miss a crucial signal, such as SIGTERM or SIGINT,
-        * that may arrive just before we enter poll(). We will block the
-        * key signals, then check whether any have arrived - if so, we return
-        * before calling poll(). If not, we'll re-enable the signals
-        * in the ppoll() call.
-        */
-
-       sigemptyset(&origsigs);
-       if (m->handle_signals) {
-               /* Main pthread that handles the app signals */
-               if (frr_sigevent_check(&origsigs)) {
-                       /* Signal to process - restore signal mask and return */
-                       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
-                       num = -1;
-                       *eintr_p = true;
-                       goto done;
-               }
-       } else {
-               /* Don't make any changes for the non-main pthreads */
-               pthread_sigmask(SIG_SETMASK, NULL, &origsigs);
-       }
-
-#if defined(HAVE_PPOLL)
-       struct timespec ts, *tsp;
-
-       if (timeout >= 0) {
-               ts.tv_sec = timeout / 1000;
-               ts.tv_nsec = (timeout % 1000) * 1000000;
-               tsp = &ts;
-       } else
-               tsp = NULL;
-
-       num = ppoll(m->handler.copy, count + 1, tsp, &origsigs);
-       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
-#else
-       /* Not ideal - there is a race after we restore the signal mask */
-       pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
-       num = poll(m->handler.copy, count + 1, timeout);
-#endif
-
-done:
-
-       if (num < 0 && errno == EINTR)
-               *eintr_p = true;
-
-       if (num > 0 && m->handler.copy[count].revents != 0 && num--)
-               while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
-                       ;
-
-       rcu_read_lock();
-
-       return num;
-}
-
-/* Add new read thread. */
-void _thread_add_read_write(const struct xref_threadsched *xref,
-                           struct thread_master *m,
-                           void (*func)(struct thread *), void *arg, int fd,
-                           struct thread **t_ptr)
-{
-       int dir = xref->thread_type;
-       struct thread *thread = NULL;
-       struct thread **thread_array;
-
-       if (dir == THREAD_READ)
-               frrtrace(9, frr_libfrr, schedule_read, m,
-                        xref->funcname, xref->xref.file, xref->xref.line,
-                        t_ptr, fd, 0, arg, 0);
-       else
-               frrtrace(9, frr_libfrr, schedule_write, m,
-                        xref->funcname, xref->xref.file, xref->xref.line,
-                        t_ptr, fd, 0, arg, 0);
-
-       assert(fd >= 0);
-       if (fd >= m->fd_limit)
-               assert(!"Number of FD's open is greater than FRR currently configured to handle, aborting");
-
-       frr_with_mutex (&m->mtx) {
-               if (t_ptr && *t_ptr)
-                       // thread is already scheduled; don't reschedule
-                       break;
-
-               /* default to a new pollfd */
-               nfds_t queuepos = m->handler.pfdcount;
-
-               if (dir == THREAD_READ)
-                       thread_array = m->read;
-               else
-                       thread_array = m->write;
-
-               /* if we already have a pollfd for our file descriptor, find and
-                * use it */
-               for (nfds_t i = 0; i < m->handler.pfdcount; i++)
-                       if (m->handler.pfds[i].fd == fd) {
-                               queuepos = i;
-
-#ifdef DEV_BUILD
-                               /*
-                                * What happens if we have a thread already
-                                * created for this event?
-                                */
-                               if (thread_array[fd])
-                                       assert(!"Thread already scheduled for file descriptor");
-#endif
-                               break;
-                       }
-
-               /* make sure we have room for this fd + pipe poker fd */
-               assert(queuepos + 1 < m->handler.pfdsize);
-
-               thread = thread_get(m, dir, func, arg, xref);
-
-               m->handler.pfds[queuepos].fd = fd;
-               m->handler.pfds[queuepos].events |=
-                       (dir == THREAD_READ ? POLLIN : POLLOUT);
-
-               if (queuepos == m->handler.pfdcount)
-                       m->handler.pfdcount++;
-
-               if (thread) {
-                       frr_with_mutex (&thread->mtx) {
-                               thread->u.fd = fd;
-                               thread_array[thread->u.fd] = thread;
-                       }
-
-                       if (t_ptr) {
-                               *t_ptr = thread;
-                               thread->ref = t_ptr;
-                       }
-               }
-
-               AWAKEN(m);
-       }
-}
-
-static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
-                                     struct thread_master *m,
-                                     void (*func)(struct thread *), void *arg,
-                                     struct timeval *time_relative,
-                                     struct thread **t_ptr)
-{
-       struct thread *thread;
-       struct timeval t;
-
-       assert(m != NULL);
-
-       assert(time_relative);
-
-       frrtrace(9, frr_libfrr, schedule_timer, m,
-                xref->funcname, xref->xref.file, xref->xref.line,
-                t_ptr, 0, 0, arg, (long)time_relative->tv_sec);
-
-       /* Compute expiration/deadline time. */
-       monotime(&t);
-       timeradd(&t, time_relative, &t);
-
-       frr_with_mutex (&m->mtx) {
-               if (t_ptr && *t_ptr)
-                       /* thread is already scheduled; don't reschedule */
-                       return;
-
-               thread = thread_get(m, THREAD_TIMER, func, arg, xref);
-
-               frr_with_mutex (&thread->mtx) {
-                       thread->u.sands = t;
-                       thread_timer_list_add(&m->timer, thread);
-                       if (t_ptr) {
-                               *t_ptr = thread;
-                               thread->ref = t_ptr;
-                       }
-               }
-
-               /* The timer list is sorted - if this new timer
-                * might change the time we'll wait for, give the pthread
-                * a chance to re-compute.
-                */
-               if (thread_timer_list_first(&m->timer) == thread)
-                       AWAKEN(m);
-       }
-#define ONEYEAR2SEC (60 * 60 * 24 * 365)
-       if (time_relative->tv_sec > ONEYEAR2SEC)
-               flog_err(
-                       EC_LIB_TIMER_TOO_LONG,
-                       "Timer: %pTHD is created with an expiration that is greater than 1 year",
-                       thread);
-}
-
-
-/* Add timer event thread. */
-void _thread_add_timer(const struct xref_threadsched *xref,
-                      struct thread_master *m, void (*func)(struct thread *),
-                      void *arg, long timer, struct thread **t_ptr)
-{
-       struct timeval trel;
-
-       assert(m != NULL);
-
-       trel.tv_sec = timer;
-       trel.tv_usec = 0;
-
-       _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
-}
-
-/* Add timer event thread with "millisecond" resolution */
-void _thread_add_timer_msec(const struct xref_threadsched *xref,
-                           struct thread_master *m,
-                           void (*func)(struct thread *), void *arg,
-                           long timer, struct thread **t_ptr)
-{
-       struct timeval trel;
-
-       assert(m != NULL);
-
-       trel.tv_sec = timer / 1000;
-       trel.tv_usec = 1000 * (timer % 1000);
-
-       _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
-}
-
-/* Add timer event thread with "timeval" resolution */
-void _thread_add_timer_tv(const struct xref_threadsched *xref,
-                         struct thread_master *m,
-                         void (*func)(struct thread *), void *arg,
-                         struct timeval *tv, struct thread **t_ptr)
-{
-       _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
-}
-
-/* Add simple event thread. */
-void _thread_add_event(const struct xref_threadsched *xref,
-                      struct thread_master *m, void (*func)(struct thread *),
-                      void *arg, int val, struct thread **t_ptr)
-{
-       struct thread *thread = NULL;
-
-       frrtrace(9, frr_libfrr, schedule_event, m,
-                xref->funcname, xref->xref.file, xref->xref.line,
-                t_ptr, 0, val, arg, 0);
-
-       assert(m != NULL);
-
-       frr_with_mutex (&m->mtx) {
-               if (t_ptr && *t_ptr)
-                       /* thread is already scheduled; don't reschedule */
-                       break;
-
-               thread = thread_get(m, THREAD_EVENT, func, arg, xref);
-               frr_with_mutex (&thread->mtx) {
-                       thread->u.val = val;
-                       thread_list_add_tail(&m->event, thread);
-               }
-
-               if (t_ptr) {
-                       *t_ptr = thread;
-                       thread->ref = t_ptr;
-               }
-
-               AWAKEN(m);
-       }
-}
-
-/* Thread cancellation ------------------------------------------------------ */
-
-/**
- * NOT's out the .events field of pollfd corresponding to the given file
- * descriptor. The event to be NOT'd is passed in the 'state' parameter.
- *
- * This needs to happen for both copies of pollfd's. See 'thread_fetch'
- * implementation for details.
- *
- * @param master
- * @param fd
- * @param state the event to cancel. One or more (OR'd together) of the
- * following:
- *   - POLLIN
- *   - POLLOUT
- */
-static void thread_cancel_rw(struct thread_master *master, int fd, short state,
-                            int idx_hint)
-{
-       bool found = false;
-
-       /* find the index of corresponding pollfd */
-       nfds_t i;
-
-       /* Cancel POLLHUP too just in case some bozo set it */
-       state |= POLLHUP;
-
-       /* Some callers know the index of the pfd already */
-       if (idx_hint >= 0) {
-               i = idx_hint;
-               found = true;
-       } else {
-               /* Have to look for the fd in the pfd array */
-               for (i = 0; i < master->handler.pfdcount; i++)
-                       if (master->handler.pfds[i].fd == fd) {
-                               found = true;
-                               break;
-                       }
-       }
-
-       if (!found) {
-               zlog_debug(
-                       "[!] Received cancellation request for nonexistent rw job");
-               zlog_debug("[!] threadmaster: %s | fd: %d",
-                          master->name ? master->name : "", fd);
-               return;
-       }
-
-       /* NOT out event. */
-       master->handler.pfds[i].events &= ~(state);
-
-       /* If all events are canceled, delete / resize the pollfd array. */
-       if (master->handler.pfds[i].events == 0) {
-               memmove(master->handler.pfds + i, master->handler.pfds + i + 1,
-                       (master->handler.pfdcount - i - 1)
-                               * sizeof(struct pollfd));
-               master->handler.pfdcount--;
-               master->handler.pfds[master->handler.pfdcount].fd = 0;
-               master->handler.pfds[master->handler.pfdcount].events = 0;
-       }
-
-       /* If we have the same pollfd in the copy, perform the same operations,
-        * otherwise return. */
-       if (i >= master->handler.copycount)
-               return;
-
-       master->handler.copy[i].events &= ~(state);
-
-       if (master->handler.copy[i].events == 0) {
-               memmove(master->handler.copy + i, master->handler.copy + i + 1,
-                       (master->handler.copycount - i - 1)
-                               * sizeof(struct pollfd));
-               master->handler.copycount--;
-               master->handler.copy[master->handler.copycount].fd = 0;
-               master->handler.copy[master->handler.copycount].events = 0;
-       }
-}
-
-/*
- * Process task cancellation given a task argument: iterate through the
- * various lists of tasks, looking for any that match the argument.
- */
-static void cancel_arg_helper(struct thread_master *master,
-                             const struct cancel_req *cr)
-{
-       struct thread *t;
-       nfds_t i;
-       int fd;
-       struct pollfd *pfd;
-
-       /* We're only processing arg-based cancellations here. */
-       if (cr->eventobj == NULL)
-               return;
-
-       /* First process the ready lists. */
-       frr_each_safe(thread_list, &master->event, t) {
-               if (t->arg != cr->eventobj)
-                       continue;
-               thread_list_del(&master->event, t);
-               if (t->ref)
-                       *t->ref = NULL;
-               thread_add_unuse(master, t);
-       }
-
-       frr_each_safe(thread_list, &master->ready, t) {
-               if (t->arg != cr->eventobj)
-                       continue;
-               thread_list_del(&master->ready, t);
-               if (t->ref)
-                       *t->ref = NULL;
-               thread_add_unuse(master, t);
-       }
-
-       /* If requested, stop here and ignore io and timers */
-       if (CHECK_FLAG(cr->flags, THREAD_CANCEL_FLAG_READY))
-               return;
-
-       /* Check the io tasks */
-       for (i = 0; i < master->handler.pfdcount;) {
-               pfd = master->handler.pfds + i;
-
-               if (pfd->events & POLLIN)
-                       t = master->read[pfd->fd];
-               else
-                       t = master->write[pfd->fd];
-
-               if (t && t->arg == cr->eventobj) {
-                       fd = pfd->fd;
-
-                       /* Found a match to cancel: clean up fd arrays */
-                       thread_cancel_rw(master, pfd->fd, pfd->events, i);
-
-                       /* Clean up thread arrays */
-                       master->read[fd] = NULL;
-                       master->write[fd] = NULL;
-
-                       /* Clear caller's ref */
-                       if (t->ref)
-                               *t->ref = NULL;
-
-                       thread_add_unuse(master, t);
-
-                       /* Don't increment 'i' since the cancellation will have
-                        * removed the entry from the pfd array
-                        */
-               } else
-                       i++;
-       }
-
-       /* Check the timer tasks */
-       t = thread_timer_list_first(&master->timer);
-       while (t) {
-               struct thread *t_next;
-
-               t_next = thread_timer_list_next(&master->timer, t);
-
-               if (t->arg == cr->eventobj) {
-                       thread_timer_list_del(&master->timer, t);
-                       if (t->ref)
-                               *t->ref = NULL;
-                       thread_add_unuse(master, t);
-               }
-
-               t = t_next;
-       }
-}
-
-/**
- * Process cancellation requests.
- *
- * This may only be run from the pthread which owns the thread_master.
- *
- * @param master the thread master to process
- * @REQUIRE master->mtx
- */
-static void do_thread_cancel(struct thread_master *master)
-{
-       struct thread_list_head *list = NULL;
-       struct thread **thread_array = NULL;
-       struct thread *thread;
-       struct cancel_req *cr;
-       struct listnode *ln;
-
-       for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
-               /*
-                * If this is an event object cancellation, search
-                * through task lists deleting any tasks which have the
-                * specified argument - use this handy helper function.
-                */
-               if (cr->eventobj) {
-                       cancel_arg_helper(master, cr);
-                       continue;
-               }
-
-               /*
-                * The pointer varies depending on whether the cancellation
-                * request was made asynchronously or not. If it was, we
-                * need to check whether the thread even exists anymore
-                * before cancelling it.
-                */
-               thread = (cr->thread) ? cr->thread : *cr->threadref;
-
-               if (!thread)
-                       continue;
-
-               list = NULL;
-               thread_array = NULL;
-
-               /* Determine the appropriate queue to cancel the thread from */
-               switch (thread->type) {
-               case THREAD_READ:
-                       thread_cancel_rw(master, thread->u.fd, POLLIN, -1);
-                       thread_array = master->read;
-                       break;
-               case THREAD_WRITE:
-                       thread_cancel_rw(master, thread->u.fd, POLLOUT, -1);
-                       thread_array = master->write;
-                       break;
-               case THREAD_TIMER:
-                       thread_timer_list_del(&master->timer, thread);
-                       break;
-               case THREAD_EVENT:
-                       list = &master->event;
-                       break;
-               case THREAD_READY:
-                       list = &master->ready;
-                       break;
-               default:
-                       continue;
-                       break;
-               }
-
-               if (list) {
-                       thread_list_del(list, thread);
-               } else if (thread_array) {
-                       thread_array[thread->u.fd] = NULL;
-               }
-
-               if (thread->ref)
-                       *thread->ref = NULL;
-
-               thread_add_unuse(thread->master, thread);
-       }
-
-       /* Delete and free all cancellation requests */
-       if (master->cancel_req)
-               list_delete_all_node(master->cancel_req);
-
-       /* Wake up any threads which may be blocked in thread_cancel_async() */
-       master->canceled = true;
-       pthread_cond_broadcast(&master->cancel_cond);
-}
-
-/*
- * Helper function used for multiple flavors of arg-based cancellation.
- */
-static void cancel_event_helper(struct thread_master *m, void *arg, int flags)
-{
-       struct cancel_req *cr;
-
-       assert(m->owner == pthread_self());
-
-       /* Only worth anything if caller supplies an arg. */
-       if (arg == NULL)
-               return;
-
-       cr = XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
-
-       cr->flags = flags;
-
-       frr_with_mutex (&m->mtx) {
-               cr->eventobj = arg;
-               listnode_add(m->cancel_req, cr);
-               do_thread_cancel(m);
-       }
-}
-
-/**
- * Cancel any events which have the specified argument.
- *
- * MT-Unsafe
- *
- * @param m the thread_master to cancel from
- * @param arg the argument passed when creating the event
- */
-void thread_cancel_event(struct thread_master *master, void *arg)
-{
-       cancel_event_helper(master, arg, 0);
-}
-
-/*
- * Cancel ready tasks with an arg matching 'arg'
- *
- * MT-Unsafe
- *
- * @param m the thread_master to cancel from
- * @param arg the argument passed when creating the event
- */
-void thread_cancel_event_ready(struct thread_master *m, void *arg)
-{
-
-       /* Only cancel ready/event tasks */
-       cancel_event_helper(m, arg, THREAD_CANCEL_FLAG_READY);
-}
-
-/**
- * Cancel a specific task.
- *
- * MT-Unsafe
- *
- * @param thread task to cancel
- */
-void thread_cancel(struct thread **thread)
-{
-       struct thread_master *master;
-
-       if (thread == NULL || *thread == NULL)
-               return;
-
-       master = (*thread)->master;
-
-       frrtrace(9, frr_libfrr, thread_cancel, master,
-                (*thread)->xref->funcname, (*thread)->xref->xref.file,
-                (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
-                (*thread)->u.val, (*thread)->arg, (*thread)->u.sands.tv_sec);
-
-       assert(master->owner == pthread_self());
-
-       frr_with_mutex (&master->mtx) {
-               struct cancel_req *cr =
-                       XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
-               cr->thread = *thread;
-               listnode_add(master->cancel_req, cr);
-               do_thread_cancel(master);
-       }
-
-       *thread = NULL;
-}
-
-/**
- * Asynchronous cancellation.
- *
- * Called with either a struct thread ** or void * to an event argument,
- * this function posts the correct cancellation request and blocks until it is
- * serviced.
- *
- * If the thread is currently running, execution blocks until it completes.
- *
- * The last two parameters are mutually exclusive, i.e. if you pass one the
- * other must be NULL.
- *
- * When the cancellation procedure executes on the target thread_master, the
- * thread * provided is checked for nullity. If it is null, the thread is
- * assumed to no longer exist and the cancellation request is a no-op. Thus
- * users of this API must pass a back-reference when scheduling the original
- * task.
- *
- * MT-Safe
- *
- * @param master the thread master with the relevant event / task
- * @param thread pointer to thread to cancel
- * @param eventobj the event
- */
-void thread_cancel_async(struct thread_master *master, struct thread **thread,
-                        void *eventobj)
-{
-       assert(!(thread && eventobj) && (thread || eventobj));
-
-       if (thread && *thread)
-               frrtrace(9, frr_libfrr, thread_cancel_async, master,
-                        (*thread)->xref->funcname, (*thread)->xref->xref.file,
-                        (*thread)->xref->xref.line, NULL, (*thread)->u.fd,
-                        (*thread)->u.val, (*thread)->arg,
-                        (*thread)->u.sands.tv_sec);
-       else
-               frrtrace(9, frr_libfrr, thread_cancel_async, master, NULL, NULL,
-                        0, NULL, 0, 0, eventobj, 0);
-
-       assert(master->owner != pthread_self());
-
-       frr_with_mutex (&master->mtx) {
-               master->canceled = false;
-
-               if (thread) {
-                       struct cancel_req *cr =
-                               XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
-                       cr->threadref = thread;
-                       listnode_add(master->cancel_req, cr);
-               } else if (eventobj) {
-                       struct cancel_req *cr =
-                               XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
-                       cr->eventobj = eventobj;
-                       listnode_add(master->cancel_req, cr);
-               }
-               AWAKEN(master);
-
-               while (!master->canceled)
-                       pthread_cond_wait(&master->cancel_cond, &master->mtx);
-       }
-
-       if (thread)
-               *thread = NULL;
-}
-/* ------------------------------------------------------------------------- */
-
-static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers,
-                                        struct timeval *timer_val)
-{
-       if (!thread_timer_list_count(timers))
-               return NULL;
-
-       struct thread *next_timer = thread_timer_list_first(timers);
-       monotime_until(&next_timer->u.sands, timer_val);
-       return timer_val;
-}
-
-static struct thread *thread_run(struct thread_master *m, struct thread *thread,
-                                struct thread *fetch)
-{
-       *fetch = *thread;
-       thread_add_unuse(m, thread);
-       return fetch;
-}
-
-static int thread_process_io_helper(struct thread_master *m,
-                                   struct thread *thread, short state,
-                                   short actual_state, int pos)
-{
-       struct thread **thread_array;
-
-       /*
-        * poll() clears the .events field, but the pollfd array we
-        * pass to poll() is a copy of the one used to schedule threads.
-        * We need to synchronize state between the two here by applying
-        * the same changes poll() made on the copy of the "real" pollfd
-        * array.
-        *
-        * This cleans up a possible infinite loop where we refuse
-        * to respond to a poll event but poll is insistent that
-        * we should.
-        */
-       m->handler.pfds[pos].events &= ~(state);
-
-       if (!thread) {
-               if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
-                       flog_err(EC_LIB_NO_THREAD,
-                                "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!",
-                                m->handler.pfds[pos].fd, actual_state);
-               return 0;
-       }
-
-       if (thread->type == THREAD_READ)
-               thread_array = m->read;
-       else
-               thread_array = m->write;
-
-       thread_array[thread->u.fd] = NULL;
-       thread_list_add_tail(&m->ready, thread);
-       thread->type = THREAD_READY;
-
-       return 1;
-}
-
-/**
- * Process I/O events.
- *
- * Walks through file descriptor array looking for those pollfds whose .revents
- * field has something interesting. Deletes any invalid file descriptors.
- *
- * @param m the thread master
- * @param num the number of active file descriptors (return value of poll())
- */
-static void thread_process_io(struct thread_master *m, unsigned int num)
-{
-       unsigned int ready = 0;
-       struct pollfd *pfds = m->handler.copy;
-
-       for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) {
-               /* no event for current fd? immediately continue */
-               if (pfds[i].revents == 0)
-                       continue;
-
-               ready++;
-
-               /*
-                * Unless someone has called thread_cancel from another
-                * pthread, the only thing that could have changed in
-                * m->handler.pfds while we were asleep is the .events
-                * field in a given pollfd. Barring thread_cancel() that
-                * value should be a superset of the values we have in our
-                * copy, so there's no need to update it. Similarily,
-                * barring deletion, the fd should still be a valid index
-                * into the master's pfds.
-                *
-                * We are including POLLERR here to do a READ event
-                * this is because the read should fail and the
-                * read function should handle it appropriately
-                */
-               if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
-                       thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
-                                                pfds[i].revents, i);
-               }
-               if (pfds[i].revents & POLLOUT)
-                       thread_process_io_helper(m, m->write[pfds[i].fd],
-                                                POLLOUT, pfds[i].revents, i);
-
-               /* if one of our file descriptors is garbage, remove the same
-                * from
-                * both pfds + update sizes and index */
-               if (pfds[i].revents & POLLNVAL) {
-                       memmove(m->handler.pfds + i, m->handler.pfds + i + 1,
-                               (m->handler.pfdcount - i - 1)
-                                       * sizeof(struct pollfd));
-                       m->handler.pfdcount--;
-                       m->handler.pfds[m->handler.pfdcount].fd = 0;
-                       m->handler.pfds[m->handler.pfdcount].events = 0;
-
-                       memmove(pfds + i, pfds + i + 1,
-                               (m->handler.copycount - i - 1)
-                                       * sizeof(struct pollfd));
-                       m->handler.copycount--;
-                       m->handler.copy[m->handler.copycount].fd = 0;
-                       m->handler.copy[m->handler.copycount].events = 0;
-
-                       i--;
-               }
-       }
-}
-
-/* Add all timers that have popped to the ready list. */
-static unsigned int thread_process_timers(struct thread_master *m,
-                                         struct timeval *timenow)
-{
-       struct timeval prev = *timenow;
-       bool displayed = false;
-       struct thread *thread;
-       unsigned int ready = 0;
-
-       while ((thread = thread_timer_list_first(&m->timer))) {
-               if (timercmp(timenow, &thread->u.sands, <))
-                       break;
-               prev = thread->u.sands;
-               prev.tv_sec += 4;
-               /*
-                * If the timer would have popped 4 seconds in the
-                * past then we are in a situation where we are
-                * really getting behind on handling of events.
-                * Let's log it and do the right thing with it.
-                */
-               if (timercmp(timenow, &prev, >)) {
-                       atomic_fetch_add_explicit(
-                               &thread->hist->total_starv_warn, 1,
-                               memory_order_seq_cst);
-                       if (!displayed && !thread->ignore_timer_late) {
-                               flog_warn(
-                                       EC_LIB_STARVE_THREAD,
-                                       "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago",
-                                       thread);
-                               displayed = true;
-                       }
-               }
-
-               thread_timer_list_pop(&m->timer);
-               thread->type = THREAD_READY;
-               thread_list_add_tail(&m->ready, thread);
-               ready++;
-       }
-
-       return ready;
-}
-
-/* process a list en masse, e.g. for event thread lists */
-static unsigned int thread_process(struct thread_list_head *list)
-{
-       struct thread *thread;
-       unsigned int ready = 0;
-
-       while ((thread = thread_list_pop(list))) {
-               thread->type = THREAD_READY;
-               thread_list_add_tail(&thread->master->ready, thread);
-               ready++;
-       }
-       return ready;
-}
-
-
-/* Fetch next ready thread. */
-struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
-{
-       struct thread *thread = NULL;
-       struct timeval now;
-       struct timeval zerotime = {0, 0};
-       struct timeval tv;
-       struct timeval *tw = NULL;
-       bool eintr_p = false;
-       int num = 0;
-
-       do {
-               /* Handle signals if any */
-               if (m->handle_signals)
-                       frr_sigevent_process();
-
-               pthread_mutex_lock(&m->mtx);
-
-               /* Process any pending cancellation requests */
-               do_thread_cancel(m);
-
-               /*
-                * Attempt to flush ready queue before going into poll().
-                * This is performance-critical. Think twice before modifying.
-                */
-               if ((thread = thread_list_pop(&m->ready))) {
-                       fetch = thread_run(m, thread, fetch);
-                       if (fetch->ref)
-                               *fetch->ref = NULL;
-                       pthread_mutex_unlock(&m->mtx);
-                       if (!m->ready_run_loop)
-                               GETRUSAGE(&m->last_getrusage);
-                       m->ready_run_loop = true;
-                       break;
-               }
-
-               m->ready_run_loop = false;
-               /* otherwise, tick through scheduling sequence */
-
-               /*
-                * Post events to ready queue. This must come before the
-                * following block since events should occur immediately
-                */
-               thread_process(&m->event);
-
-               /*
-                * If there are no tasks on the ready queue, we will poll()
-                * until a timer expires or we receive I/O, whichever comes
-                * first. The strategy for doing this is:
-                *
-                * - If there are events pending, set the poll() timeout to zero
-                * - If there are no events pending, but there are timers
-                * pending, set the timeout to the smallest remaining time on
-                * any timer.
-                * - If there are neither timers nor events pending, but there
-                * are file descriptors pending, block indefinitely in poll()
-                * - If nothing is pending, it's time for the application to die
-                *
-                * In every case except the last, we need to hit poll() at least
-                * once per loop to avoid starvation by events
-                */
-               if (!thread_list_count(&m->ready))
-                       tw = thread_timer_wait(&m->timer, &tv);
-
-               if (thread_list_count(&m->ready) ||
-                               (tw && !timercmp(tw, &zerotime, >)))
-                       tw = &zerotime;
-
-               if (!tw && m->handler.pfdcount == 0) { /* die */
-                       pthread_mutex_unlock(&m->mtx);
-                       fetch = NULL;
-                       break;
-               }
-
-               /*
-                * Copy pollfd array + # active pollfds in it. Not necessary to
-                * copy the array size as this is fixed.
-                */
-               m->handler.copycount = m->handler.pfdcount;
-               memcpy(m->handler.copy, m->handler.pfds,
-                      m->handler.copycount * sizeof(struct pollfd));
-
-               pthread_mutex_unlock(&m->mtx);
-               {
-                       eintr_p = false;
-                       num = fd_poll(m, tw, &eintr_p);
-               }
-               pthread_mutex_lock(&m->mtx);
-
-               /* Handle any errors received in poll() */
-               if (num < 0) {
-                       if (eintr_p) {
-                               pthread_mutex_unlock(&m->mtx);
-                               /* loop around to signal handler */
-                               continue;
-                       }
-
-                       /* else die */
-                       flog_err(EC_LIB_SYSTEM_CALL, "poll() error: %s",
-                                safe_strerror(errno));
-                       pthread_mutex_unlock(&m->mtx);
-                       fetch = NULL;
-                       break;
-               }
-
-               /* Post timers to ready queue. */
-               monotime(&now);
-               thread_process_timers(m, &now);
-
-               /* Post I/O to ready queue. */
-               if (num > 0)
-                       thread_process_io(m, num);
-
-               pthread_mutex_unlock(&m->mtx);
-
-       } while (!thread && m->spin);
-
-       return fetch;
-}
-
-static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
-{
-       return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
-               + (a.tv_usec - b.tv_usec));
-}
-
-unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
-                                  unsigned long *cputime)
-{
-#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
-
-#ifdef __FreeBSD__
-       /*
-        * FreeBSD appears to have an issue when calling clock_gettime
-        * with CLOCK_THREAD_CPUTIME_ID really close to each other
-        * occassionally the now time will be before the start time.
-        * This is not good and FRR is ending up with CPU HOG's
-        * when the subtraction wraps to very large numbers
-        *
-        * What we are going to do here is cheat a little bit
-        * and notice that this is a problem and just correct
-        * it so that it is impossible to happen
-        */
-       if (start->cpu.tv_sec == now->cpu.tv_sec &&
-           start->cpu.tv_nsec > now->cpu.tv_nsec)
-               now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
-       else if (start->cpu.tv_sec > now->cpu.tv_sec) {
-               now->cpu.tv_sec = start->cpu.tv_sec;
-               now->cpu.tv_nsec = start->cpu.tv_nsec + 1;
-       }
-#endif
-       *cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO
-                  + (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000;
-#else
-       /* This is 'user + sys' time.  */
-       *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
-                  + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
-#endif
-       return timeval_elapsed(now->real, start->real);
-}
-
-/* We should aim to yield after yield milliseconds, which defaults
-   to THREAD_YIELD_TIME_SLOT .
-   Note: we are using real (wall clock) time for this calculation.
-   It could be argued that CPU time may make more sense in certain
-   contexts.  The things to consider are whether the thread may have
-   blocked (in which case wall time increases, but CPU time does not),
-   or whether the system is heavily loaded with other processes competing
-   for CPU time.  On balance, wall clock time seems to make sense.
-   Plus it has the added benefit that gettimeofday should be faster
-   than calling getrusage. */
-int thread_should_yield(struct thread *thread)
-{
-       int result;
-       frr_with_mutex (&thread->mtx) {
-               result = monotime_since(&thread->real, NULL)
-                        > (int64_t)thread->yield;
-       }
-       return result;
-}
-
-void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
-{
-       frr_with_mutex (&thread->mtx) {
-               thread->yield = yield_time;
-       }
-}
-
-void thread_getrusage(RUSAGE_T *r)
-{
-       monotime(&r->real);
-       if (!cputime_enabled) {
-               memset(&r->cpu, 0, sizeof(r->cpu));
-               return;
-       }
-
-#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
-       /* not currently implemented in Linux's vDSO, but maybe at some point
-        * in the future?
-        */
-       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &r->cpu);
-#else /* !HAVE_CLOCK_THREAD_CPUTIME_ID */
-#if defined RUSAGE_THREAD
-#define FRR_RUSAGE RUSAGE_THREAD
-#else
-#define FRR_RUSAGE RUSAGE_SELF
-#endif
-       getrusage(FRR_RUSAGE, &(r->cpu));
-#endif
-}
-
-/*
- * Call a thread.
- *
- * This function will atomically update the thread's usage history. At present
- * this is the only spot where usage history is written. Nevertheless the code
- * has been written such that the introduction of writers in the future should
- * not need to update it provided the writers atomically perform only the
- * operations done here, i.e. updating the total and maximum times. In
- * particular, the maximum real and cpu times must be monotonically increasing
- * or this code is not correct.
- */
-void thread_call(struct thread *thread)
-{
-       RUSAGE_T before, after;
-
-       /* if the thread being called is the CLI, it may change cputime_enabled
-        * ("service cputime-stats" command), which can result in nonsensical
-        * and very confusing warnings
-        */
-       bool cputime_enabled_here = cputime_enabled;
-
-       if (thread->master->ready_run_loop)
-               before = thread->master->last_getrusage;
-       else
-               GETRUSAGE(&before);
-
-       thread->real = before.real;
-
-       frrtrace(9, frr_libfrr, thread_call, thread->master,
-                thread->xref->funcname, thread->xref->xref.file,
-                thread->xref->xref.line, NULL, thread->u.fd,
-                thread->u.val, thread->arg, thread->u.sands.tv_sec);
-
-       pthread_setspecific(thread_current, thread);
-       (*thread->func)(thread);
-       pthread_setspecific(thread_current, NULL);
-
-       GETRUSAGE(&after);
-       thread->master->last_getrusage = after;
-
-       unsigned long walltime, cputime;
-       unsigned long exp;
-
-       walltime = thread_consumed_time(&after, &before, &cputime);
-
-       /* update walltime */
-       atomic_fetch_add_explicit(&thread->hist->real.total, walltime,
-                                 memory_order_seq_cst);
-       exp = atomic_load_explicit(&thread->hist->real.max,
-                                  memory_order_seq_cst);
-       while (exp < walltime
-              && !atomic_compare_exchange_weak_explicit(
-                      &thread->hist->real.max, &exp, walltime,
-                      memory_order_seq_cst, memory_order_seq_cst))
-               ;
-
-       if (cputime_enabled_here && cputime_enabled) {
-               /* update cputime */
-               atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime,
-                                         memory_order_seq_cst);
-               exp = atomic_load_explicit(&thread->hist->cpu.max,
-                                          memory_order_seq_cst);
-               while (exp < cputime
-                      && !atomic_compare_exchange_weak_explicit(
-                              &thread->hist->cpu.max, &exp, cputime,
-                              memory_order_seq_cst, memory_order_seq_cst))
-                       ;
-       }
-
-       atomic_fetch_add_explicit(&thread->hist->total_calls, 1,
-                                 memory_order_seq_cst);
-       atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type,
-                                memory_order_seq_cst);
-
-       if (cputime_enabled_here && cputime_enabled && cputime_threshold
-           && cputime > cputime_threshold) {
-               /*
-                * We have a CPU Hog on our hands.  The time FRR has spent
-                * doing actual work (not sleeping) is greater than 5 seconds.
-                * Whinge about it now, so we're aware this is yet another task
-                * to fix.
-                */
-               atomic_fetch_add_explicit(&thread->hist->total_cpu_warn,
-                                         1, memory_order_seq_cst);
-               flog_warn(
-                       EC_LIB_SLOW_THREAD_CPU,
-                       "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)",
-                       thread->xref->funcname, (unsigned long)thread->func,
-                       walltime / 1000, cputime / 1000);
-
-       } else if (walltime_threshold && walltime > walltime_threshold) {
-               /*
-                * The runtime for a task is greater than 5 seconds, but the
-                * cpu time is under 5 seconds.  Let's whine about this because
-                * this could imply some sort of scheduling issue.
-                */
-               atomic_fetch_add_explicit(&thread->hist->total_wall_warn,
-                                         1, memory_order_seq_cst);
-               flog_warn(
-                       EC_LIB_SLOW_THREAD_WALL,
-                       "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)",
-                       thread->xref->funcname, (unsigned long)thread->func,
-                       walltime / 1000, cputime / 1000);
-       }
-}
-
-/* Execute thread */
-void _thread_execute(const struct xref_threadsched *xref,
-                    struct thread_master *m, void (*func)(struct thread *),
-                    void *arg, int val)
-{
-       struct thread *thread;
-
-       /* Get or allocate new thread to execute. */
-       frr_with_mutex (&m->mtx) {
-               thread = thread_get(m, THREAD_EVENT, func, arg, xref);
-
-               /* Set its event value. */
-               frr_with_mutex (&thread->mtx) {
-                       thread->add_type = THREAD_EXECUTE;
-                       thread->u.val = val;
-                       thread->ref = &thread;
-               }
-       }
-
-       /* Execute thread doing all accounting. */
-       thread_call(thread);
-
-       /* Give back or free thread. */
-       thread_add_unuse(m, thread);
-}
-
-/* Debug signal mask - if 'sigs' is NULL, use current effective mask. */
-void debug_signals(const sigset_t *sigs)
-{
-       int i, found;
-       sigset_t tmpsigs;
-       char buf[300];
-
-       /*
-        * We're only looking at the non-realtime signals here, so we need
-        * some limit value. Platform differences mean at some point we just
-        * need to pick a reasonable value.
-        */
-#if defined SIGRTMIN
-#  define LAST_SIGNAL SIGRTMIN
-#else
-#  define LAST_SIGNAL 32
-#endif
-
-
-       if (sigs == NULL) {
-               sigemptyset(&tmpsigs);
-               pthread_sigmask(SIG_BLOCK, NULL, &tmpsigs);
-               sigs = &tmpsigs;
-       }
-
-       found = 0;
-       buf[0] = '\0';
-
-       for (i = 0; i < LAST_SIGNAL; i++) {
-               char tmp[20];
-
-               if (sigismember(sigs, i) > 0) {
-                       if (found > 0)
-                               strlcat(buf, ",", sizeof(buf));
-                       snprintf(tmp, sizeof(tmp), "%d", i);
-                       strlcat(buf, tmp, sizeof(buf));
-                       found++;
-               }
-       }
-
-       if (found == 0)
-               snprintf(buf, sizeof(buf), "<none>");
-
-       zlog_debug("%s: %s", __func__, buf);
-}
-
-static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea,
-                                  const struct thread *thread)
-{
-       static const char * const types[] = {
-               [THREAD_READ] = "read",
-               [THREAD_WRITE] = "write",
-               [THREAD_TIMER] = "timer",
-               [THREAD_EVENT] = "event",
-               [THREAD_READY] = "ready",
-               [THREAD_UNUSED] = "unused",
-               [THREAD_EXECUTE] = "exec",
-       };
-       ssize_t rv = 0;
-       char info[16] = "";
-
-       if (!thread)
-               return bputs(buf, "{(thread *)NULL}");
-
-       rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg);
-
-       if (thread->type < array_size(types) && types[thread->type])
-               rv += bprintfrr(buf, " %-6s", types[thread->type]);
-       else
-               rv += bprintfrr(buf, " INVALID(%u)", thread->type);
-
-       switch (thread->type) {
-       case THREAD_READ:
-       case THREAD_WRITE:
-               snprintfrr(info, sizeof(info), "fd=%d", thread->u.fd);
-               break;
-
-       case THREAD_TIMER:
-               snprintfrr(info, sizeof(info), "r=%pTVMud", &thread->u.sands);
-               break;
-       }
-
-       rv += bprintfrr(buf, " %-12s %s() %s from %s:%d}", info,
-                       thread->xref->funcname, thread->xref->dest,
-                       thread->xref->xref.file, thread->xref->xref.line);
-       return rv;
-}
-
-printfrr_ext_autoreg_p("TH", printfrr_thread);
-static ssize_t printfrr_thread(struct fbuf *buf, struct printfrr_eargs *ea,
-                              const void *ptr)
-{
-       const struct thread *thread = ptr;
-       struct timespec remain = {};
-
-       if (ea->fmt[0] == 'D') {
-               ea->fmt++;
-               return printfrr_thread_dbg(buf, ea, thread);
-       }
-
-       if (!thread) {
-               /* need to jump over time formatting flag characters in the
-                * input format string, i.e. adjust ea->fmt!
-                */
-               printfrr_time(buf, ea, &remain,
-                             TIMEFMT_TIMER_DEADLINE | TIMEFMT_SKIP);
-               return bputch(buf, '-');
-       }
-
-       TIMEVAL_TO_TIMESPEC(&thread->u.sands, &remain);
-       return printfrr_time(buf, ea, &remain, TIMEFMT_TIMER_DEADLINE);
-}
diff --git a/lib/thread.h b/lib/thread.h
deleted file mode 100644 (file)
index 128d11b..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* Thread management routine header.
- * Copyright (C) 1998 Kunihiro Ishiguro
- */
-
-#ifndef _ZEBRA_THREAD_H
-#define _ZEBRA_THREAD_H
-
-#include <zebra.h>
-#include <pthread.h>
-#include <poll.h>
-#include "monotime.h"
-#include "frratomic.h"
-#include "typesafe.h"
-#include "xref.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern bool cputime_enabled;
-extern unsigned long cputime_threshold;
-/* capturing wallclock time is always enabled since it is fast (reading
- * hardware TSC w/o syscalls)
- */
-extern unsigned long walltime_threshold;
-
-struct rusage_t {
-#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
-       struct timespec cpu;
-#else
-       struct rusage cpu;
-#endif
-       struct timeval real;
-};
-#define RUSAGE_T        struct rusage_t
-
-#define GETRUSAGE(X) thread_getrusage(X)
-
-PREDECL_LIST(thread_list);
-PREDECL_HEAP(thread_timer_list);
-
-struct fd_handler {
-       /* number of pfd that fit in the allocated space of pfds. This is a
-        * constant and is the same for both pfds and copy.
-        */
-       nfds_t pfdsize;
-
-       /* file descriptors to monitor for i/o */
-       struct pollfd *pfds;
-       /* number of pollfds stored in pfds */
-       nfds_t pfdcount;
-
-       /* chunk used for temp copy of pollfds */
-       struct pollfd *copy;
-       /* number of pollfds stored in copy */
-       nfds_t copycount;
-};
-
-struct xref_threadsched {
-       struct xref xref;
-
-       const char *funcname;
-       const char *dest;
-       uint32_t thread_type;
-};
-
-/* Master of the theads. */
-struct thread_master {
-       char *name;
-
-       struct thread **read;
-       struct thread **write;
-       struct thread_timer_list_head timer;
-       struct thread_list_head event, ready, unuse;
-       struct list *cancel_req;
-       bool canceled;
-       pthread_cond_t cancel_cond;
-       struct hash *cpu_record;
-       int io_pipe[2];
-       int fd_limit;
-       struct fd_handler handler;
-       unsigned long alloc;
-       long selectpoll_timeout;
-       bool spin;
-       bool handle_signals;
-       pthread_mutex_t mtx;
-       pthread_t owner;
-
-       bool ready_run_loop;
-       RUSAGE_T last_getrusage;
-};
-
-/* Thread itself. */
-struct thread {
-       uint8_t type;             /* thread type */
-       uint8_t add_type;         /* thread type */
-       struct thread_list_item threaditem;
-       struct thread_timer_list_item timeritem;
-       struct thread **ref;      /* external reference (if given) */
-       struct thread_master *master; /* pointer to the struct thread_master */
-       void (*func)(struct thread *); /* event function */
-       void *arg;                    /* event argument */
-       union {
-               int val;              /* second argument of the event. */
-               int fd;               /* file descriptor in case of r/w */
-               struct timeval sands; /* rest of time sands value. */
-       } u;
-       struct timeval real;
-       struct cpu_thread_history *hist; /* cache pointer to cpu_history */
-       unsigned long yield;             /* yield time in microseconds */
-       const struct xref_threadsched *xref;   /* origin location */
-       pthread_mutex_t mtx;   /* mutex for thread.c functions */
-       bool ignore_timer_late;
-};
-
-#ifdef _FRR_ATTRIBUTE_PRINTFRR
-#pragma FRR printfrr_ext "%pTH" (struct thread *)
-#endif
-
-struct cpu_thread_history {
-       void (*func)(struct thread *);
-       atomic_size_t total_cpu_warn;
-       atomic_size_t total_wall_warn;
-       atomic_size_t total_starv_warn;
-       atomic_size_t total_calls;
-       atomic_size_t total_active;
-       struct time_stats {
-               atomic_size_t total, max;
-       } real;
-       struct time_stats cpu;
-       atomic_uint_fast32_t types;
-       const char *funcname;
-};
-
-/* Struct timeval's tv_usec one second value.  */
-#define TIMER_SECOND_MICRO 1000000L
-
-/* Thread types. */
-#define THREAD_READ           0
-#define THREAD_WRITE          1
-#define THREAD_TIMER          2
-#define THREAD_EVENT          3
-#define THREAD_READY          4
-#define THREAD_UNUSED         5
-#define THREAD_EXECUTE        6
-
-/* Thread yield time.  */
-#define THREAD_YIELD_TIME_SLOT     10 * 1000L /* 10ms */
-
-#define THREAD_TIMER_STRLEN 12
-
-/* Macros. */
-#define THREAD_ARG(X) ((X)->arg)
-#define THREAD_FD(X)  ((X)->u.fd)
-#define THREAD_VAL(X) ((X)->u.val)
-
-/*
- * Please consider this macro deprecated, and do not use it in new code.
- */
-#define THREAD_OFF(thread)                                             \
-       do {                                                           \
-               if ((thread))                                          \
-                       thread_cancel(&(thread));                      \
-       } while (0)
-
-/*
- * Macro wrappers to generate xrefs for all thread add calls.  Includes
- * file/line/function info for debugging/tracing.
- */
-#include "lib/xref.h"
-
-#define _xref_t_a(addfn, type, m, f, a, v, t)                                  \
-       ({                                                                     \
-               static const struct xref_threadsched _xref                     \
-                               __attribute__((used)) = {                      \
-                       .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__),  \
-                       .funcname = #f,                                        \
-                       .dest = #t,                                            \
-                       .thread_type = THREAD_ ## type,                        \
-               };                                                             \
-               XREF_LINK(_xref.xref);                                         \
-               _thread_add_ ## addfn(&_xref, m, f, a, v, t);                  \
-       })                                                                     \
-       /* end */
-
-#define thread_add_read(m,f,a,v,t)       _xref_t_a(read_write, READ,  m,f,a,v,t)
-#define thread_add_write(m,f,a,v,t)      _xref_t_a(read_write, WRITE, m,f,a,v,t)
-#define thread_add_timer(m,f,a,v,t)      _xref_t_a(timer,      TIMER, m,f,a,v,t)
-#define thread_add_timer_msec(m,f,a,v,t) _xref_t_a(timer_msec, TIMER, m,f,a,v,t)
-#define thread_add_timer_tv(m,f,a,v,t)   _xref_t_a(timer_tv,   TIMER, m,f,a,v,t)
-#define thread_add_event(m,f,a,v,t)      _xref_t_a(event,      EVENT, m,f,a,v,t)
-
-#define thread_execute(m,f,a,v)                                                \
-       ({                                                                     \
-               static const struct xref_threadsched _xref                     \
-                               __attribute__((used)) = {                      \
-                       .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__),  \
-                       .funcname = #f,                                        \
-                       .dest = NULL,                                          \
-                       .thread_type = THREAD_EXECUTE,                         \
-               };                                                             \
-               XREF_LINK(_xref.xref);                                         \
-               _thread_execute(&_xref, m, f, a, v);                           \
-       }) /* end */
-
-/* Prototypes. */
-extern struct thread_master *thread_master_create(const char *);
-void thread_master_set_name(struct thread_master *master, const char *name);
-extern void thread_master_free(struct thread_master *);
-extern void thread_master_free_unused(struct thread_master *);
-
-extern void _thread_add_read_write(const struct xref_threadsched *xref,
-                                  struct thread_master *master,
-                                  void (*fn)(struct thread *), void *arg,
-                                  int fd, struct thread **tref);
-
-extern void _thread_add_timer(const struct xref_threadsched *xref,
-                             struct thread_master *master,
-                             void (*fn)(struct thread *), void *arg, long t,
-                             struct thread **tref);
-
-extern void _thread_add_timer_msec(const struct xref_threadsched *xref,
-                                  struct thread_master *master,
-                                  void (*fn)(struct thread *), void *arg,
-                                  long t, struct thread **tref);
-
-extern void _thread_add_timer_tv(const struct xref_threadsched *xref,
-                                struct thread_master *master,
-                                void (*fn)(struct thread *), void *arg,
-                                struct timeval *tv, struct thread **tref);
-
-extern void _thread_add_event(const struct xref_threadsched *xref,
-                             struct thread_master *master,
-                             void (*fn)(struct thread *), void *arg, int val,
-                             struct thread **tref);
-
-extern void _thread_execute(const struct xref_threadsched *xref,
-                           struct thread_master *master,
-                           void (*fn)(struct thread *), void *arg, int val);
-
-extern void thread_cancel(struct thread **event);
-extern void thread_cancel_async(struct thread_master *, struct thread **,
-                               void *);
-/* Cancel ready tasks with an arg matching 'arg' */
-extern void thread_cancel_event_ready(struct thread_master *m, void *arg);
-/* Cancel all tasks with an arg matching 'arg', including timers and io */
-extern void thread_cancel_event(struct thread_master *m, void *arg);
-extern struct thread *thread_fetch(struct thread_master *, struct thread *);
-extern void thread_call(struct thread *);
-extern unsigned long thread_timer_remain_second(struct thread *);
-extern struct timeval thread_timer_remain(struct thread *);
-extern unsigned long thread_timer_remain_msec(struct thread *);
-extern int thread_should_yield(struct thread *);
-/* set yield time for thread */
-extern void thread_set_yield_time(struct thread *, unsigned long);
-
-/* Internal libfrr exports */
-extern void thread_getrusage(RUSAGE_T *);
-extern void thread_cmd_init(void);
-
-/* Returns elapsed real (wall clock) time. */
-extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
-                                         unsigned long *cpu_time_elapsed);
-
-/* only for use in logging functions! */
-extern pthread_key_t thread_current;
-extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
-               struct thread *t_timer);
-
-static inline bool thread_is_scheduled(struct thread *thread)
-{
-       if (thread)
-               return true;
-
-       return false;
-}
-
-/* Debug signal mask */
-void debug_signals(const sigset_t *sigs);
-
-static inline void thread_ignore_late_timer(struct thread *thread)
-{
-       thread->ignore_timer_late = true;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZEBRA_THREAD_H */
index 3dcae0282f689ac15c2e15cd46c0f3473dcc9c91..c6bc29d968598de14046c28a17d42010d1b89da1 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -22,7 +22,7 @@
 #include <stdio.h>
 
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "command.h"
 #include "sockunion.h"
index b302c14913628b149c497c2918bb5770317a5dd7..52453d0daae2432de452386fc4188f84b69a7b40 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -18,7 +18,7 @@
 #include <regex.h>
 #endif /* HAVE_LIBPCRE2_POSIX */
 
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "sockunion.h"
 #include "qobj.h"
index 4aca23481beea650f1a32fd62a9191e48a4707fc..bd12105a3fa27f57d58f3b835bf17dcbaca4bb0f 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include "zebra.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "wheel.h"
 #include "log.h"
index 5477aadd6525de5f6505cd96e3e72d1f5f176cd2..e1ab4c48d170f8ae51a597ed61e33b8bab7f1980 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #include <zebra.h>
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "workqueue.h"
 #include "linklist.h"
index 0e49d655280d3e3a7c9d9fd41f499dc70eba2b74..2cd80cc58567dc548e592eba65b6821ff266c0d8 100644 (file)
@@ -14,7 +14,7 @@
 #include "vrf_int.h"
 #include "if.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "zclient.h"
 #include "memory.h"
 #include "table.h"
index e05720fd9e7a8d87ddbf83a2b2b296f840e99515..d379ff8d3d3830a3a7b6cd23a051ef42c650e0b7 100644 (file)
@@ -48,7 +48,7 @@
 #include "frrcu.h"
 #include "zlog.h"
 #include "libfrr_trace.h"
-#include "thread.h"
+#include "event.h"
 
 DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE,  "log message");
 DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF,   "log thread-local buffer");
index 5264dda0f8f02e827370790140180ca26b5a5268..23cad003447e6063181a78f532b891450f43fd13 100644 (file)
@@ -26,7 +26,7 @@
 #include "frr_pthread.h"
 #include "command.h"
 #include "monotime.h"
-#include "thread.h"
+#include "event.h"
 
 #include "lib/version.h"
 #include "lib/lib_errors.h"
index 2957b2908f3a0fb78d5343a7b16f39ae4cd0f1e2..22c0c4c044e0ddfff1a828c2c49132b64e85fb66 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <zebra.h>
-#include "thread.h"
+#include "event.h"
 #include "sockopt.h"
 #include "network.h"
 #include "libfrr.h"
index 75def3a05e0e02a824b2c964af40a6b50b18c2bd..600a5f564b74d65cc3c31d552fc572ded6c20c83 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 #include "md5.h"
-#include "thread.h"
+#include "event.h"
 #include "xref.h"
 
 #include "mgmt_fe_client.h"
index 877659b4c00f9ae5b2f157c54e484f39edd867e9..552730d123c99a3e420c9fe4f49b075429bc6551 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/neighbour.h>
 #include <linux/netfilter/nfnetlink_log.h>
 
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "prefix.h"
 #include "nhrpd.h"
index 42c6c2fbba765e629618ece4b3fb3d63e157294e..ac1c8f9eb96fbff80453e4cc07efb59eab5209de 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "zebra.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "nhrpd.h"
 
index 9c11890831527478cdab60bc4e1d40319fa5841a..25f5a701bcd5b46e9617a95a336280e42fa09f7c 100644 (file)
@@ -11,7 +11,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include "thread.h"
+#include "event.h"
 #include "zbuf.h"
 #include "log.h"
 #include "nhrpd.h"
index d396f510ed8177f20a70f86e9cc92060dc01ac86..7a0c3ba493c53a2aa4d49448133d2a2fd73061eb 100644 (file)
@@ -11,7 +11,7 @@
 #include "zebra.h"
 #include "linklist.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 
 #include "nhrpd.h"
 #include "os.h"
index 10d3c8f82fc84b4051e6ffcfc7ddcdad79e5b37a..88bb1f871e3644597f044c0dcf7fa723e7b44502 100644 (file)
@@ -12,7 +12,7 @@
 #include "zebra.h"
 #include "privs.h"
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "sigevent.h"
 #include "lib/version.h"
 #include "log.h"
index cdd79e25f4a3ee7c6024fd12020a1d17b73ebc25..e37dfb5d8b8dc07fce26a8ce939270adf770e657 100644 (file)
@@ -18,7 +18,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
-#include "thread.h"
+#include "event.h"
 #include "nhrpd.h"
 #include "netlink.h"
 #include "znl.h"
index 49f881df1f6a136810b727deffdccc7a5168d349..358d1b94c521c79f86010e81833476cd0a6e7d01 100644 (file)
@@ -6,7 +6,7 @@
 #include "zebra.h"
 #include "zbuf.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "nhrpd.h"
 #include "nhrp_protocol.h"
 
index ecf8aa0b132242458a1bdfc7646dd108695ec871..d201eb6cc066c81b1181b810d3b3c57b43c176ba 100644 (file)
@@ -10,7 +10,7 @@
 #include <netinet/if_ether.h>
 #include "nhrpd.h"
 #include "zbuf.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 
 #include "nhrp_protocol.h"
index 9b92cdffc383adf6aaf8e818fc7bba8dc823912d..25ce59a401287ee975b197e3da3f3f937cda0947 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "zebra.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "network.h"
 
index 90fb1d67c285532e7afcdb8583323ee5957ff840..e5516ba727b2d3e4311ab907daa7f8dc4bfd09d0 100644 (file)
@@ -10,7 +10,7 @@
 #include "nhrpd.h"
 #include "table.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "nhrp_protocol.h"
 
index bffb2f6e948ddca22f176763dc998aa2aa16de9f..65e9af854ee5f901fdc18305c49f5be579cfcefa 100644 (file)
@@ -7,7 +7,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "hash.h"
-#include "thread.h"
+#include "event.h"
 #include "jhash.h"
 
 #include "nhrpd.h"
index 1dbb4e4f5eb2f3cfa1bcfab39e0cf2bf64ddbcd4..880e0c253faedafc0dc1c87012489170c0776b9b 100644 (file)
@@ -11,7 +11,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include "thread.h"
+#include "event.h"
 #include "zbuf.h"
 #include "log.h"
 #include "lib_errors.h"
index 5b2b204dd8855901d5b2d3fd2d2a5f3e9efa11a2..407de01c5397f667ad5ff7d147e6845c4a6576f5 100644 (file)
@@ -12,7 +12,7 @@
 #include "vty.h"
 #include "linklist.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "plist.h"
 #include "filter.h"
 
index 5795690a781e6e7696223c6342952e78f3d2c1f5..e7fefb72a7c7bbb19368f771cafa9cf8d979be84 100644 (file)
@@ -8,7 +8,7 @@
 #include "log.h"
 #include "memory.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "if.h"
index 57c873b53b71003df5a7ac6c751c98f232eb2ae9..8924c00a58658f2468fb682a3598c5c7de0708d0 100644 (file)
@@ -13,7 +13,7 @@
 #include "routemap.h"
 #include "table.h"
 #include "plist.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "lib/northbound_cli.h"
 
index 6cc9c3013b2450a195f86a0565c7c153921173d5..1b879ae2809bfbfdb2ba63a15335365049c36a43 100644 (file)
@@ -11,7 +11,7 @@
 #include "linklist.h"
 #include "memory.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "zclient.h"
index d519b0e1199d4971244e4abdc96dda6aee90d58d..a782d97304bb696516c780b12fac854b2b2a1aa7 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "command.h"
index 7afb47c75253ee2e5bde1bccc181c20e578e2a27..5f0c3cf934e2d36361ad01e6a29b6e0309258ca6 100644 (file)
@@ -9,7 +9,7 @@
 #include "if.h"
 #include "log.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "plist.h"
 #include "zclient.h"
index e7ce2f5f723e1769c07f6f394990f01823c9fe3a..d57e56bb3704dbc8ebeb1f9177f3e3bd3bedcbce 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "log.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "if.h"
 #include "prefix.h"
index fe085b4cb4ed8b34459e328db4bcf06ba9cce3e5..d93115adc14bce088610cbb98284e97f226b6fd0 100644 (file)
@@ -12,7 +12,7 @@
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "checksum.h"
 #include "frrstr.h"
 
index abc460249d684a7ed2dca8dd0c407cc178b7eb60..6b5134a2b86d4df96e167180c37947fd152c7208 100644 (file)
@@ -9,7 +9,7 @@
 #include <stdlib.h>
 
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "command.h"
 #include "vty.h"
index a499190a11cf83638981eef27ff39a99b69762b3..45d03bafe7ab81d5e93ea738e3e3b64d17f13d2d 100644 (file)
@@ -9,7 +9,7 @@
 #include "log.h"
 #include "vty.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "lib_errors.h"
 #include "checksum.h"
index 5ab5a49a4b3d7932493915776dbed44cc824b030..c90603e1ad616fedbf9cdf1e9cea1ffe04665483 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "log.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "command.h"
index d62a3a63223df608c3bf15ef4887da6486a773fe..cd3b742def8e317fb04dea47ff216401e74b8f98 100644 (file)
@@ -13,7 +13,7 @@
 #include "vty.h"
 #include "linklist.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "plist.h"
 #include "filter.h"
 
index 112934bf1eb25021e9349f01c3b1dbc8fdc22b85..474cca0f3cff96a94562c2c5d64c5004ac706477 100644 (file)
@@ -13,7 +13,7 @@
 #include "vty.h"
 #include "prefix.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "lib_errors.h"
 
 #include "ospf6_lsa.h"
index bd5aedb45efde32ede8e610da041305127ae87f6..029848386306c7e4e041bbea523513833216f50b 100644 (file)
@@ -11,7 +11,7 @@
 #include "linklist.h"
 #include "prefix.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "defaults.h"
 #include "lib/json.h"
index 257a0f2b0eaf6b0de6ca0db61848a083a55cc83c..eea487012c8d4cef8d1e2863605ac474a5164ef4 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "command.h"
index 234a0e881d9f89dbcebda659827442b927571af4..3a2eb71c3ef6d8268c3ecd9352410b25ca4af326 100644 (file)
@@ -7,7 +7,7 @@
 #define OSPF6D_H
 
 #include "libospf.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 
 DECLARE_MGROUP(OSPF6D);
index c5bbc01501595abcaf13e722bed76830b0755941..a29c4222777d1030777c5e32c23507b802c4733a 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "linklist.h"
 #include "if.h"
index cbc53ad3533fed42a517e5d346886d6d23bb3536..970a039d8182035f34558cc86ae225ff657b45a0 100644 (file)
@@ -43,7 +43,7 @@ struct zebra_privs_t ospfd_privs = {.user = NULL,
    free to use any thread library (like pthreads). */
 
 #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 
 /* Local portnumber for async channel. Note that OSPF API library will also
index 8f177cbce168129111ba95b2fdb0604b4c966525..91f4d77a860ab5d44391c6b02a968ab6beb22b66 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index 3cb1287be5d04cd8f12130540d2bdf8421c4a045..922696f8bdde29bce1d6f19473ec15b0e6b6122f 100644 (file)
@@ -18,7 +18,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "buffer.h"
index 086b5660b1daabf70407e6675afa37b2ed978afb..cc1ca6647059bc82b9e760b261b3b444bc4f728c 100644 (file)
@@ -18,7 +18,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "buffer.h"
index 6eada0b1a4276d9e7138412c8ba927e2c5fcef79..85b5377e5fc6cd2585e5571e2b340be6b58d9254 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index b43f0cb378c2186fdcc2e72746054a3c136de9e6..ad7dac0abdde136db5b2c861e93e5374741ba43c 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "hash.h"
 #include "linklist.h"
index 0b0016745d421e64ffd8f1fe2d84a104a56f36f5..3ed54d3bfb74543771ebaeb97fec056af4ec6efb 100644 (file)
@@ -12,7 +12,7 @@
 #include "linklist.h"
 #include "memory.h"
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "zclient.h"
index b74b84e37da233026674701ba8fd0c87271263a2..d712d7b5fea05680ea7a5794f913d6ae0aa8b935 100644 (file)
@@ -9,7 +9,7 @@
 #include "lib/bfd.h"
 #include "monotime.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "command.h"
 #include "stream.h"
index 5faaed076b4019380652de2533953cbd57cd37ed..28f368e37f804a2518648b4585c3d0b3239047bf 100644 (file)
@@ -25,7 +25,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "network.h"
index d0453bbc4ad580e3cef5bc6b762562f9b64b1f83..99bc4249fa2a86af02b7d268e8bdcd5648c59437 100644 (file)
@@ -12,7 +12,7 @@
 #include "if.h"
 #include "command.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "log.h"
 #include "zclient.h"
index 07ce0d66eaf63d523587429a5759a4dcbfe931c7..522c9b71b621fda85a7c1df260f13e8eb7577976 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index d3c9626d9ae8ad317797ba104ea14ff48dd2fb3b..b4bf6cf3d07df66b0da90b3cee9610bd42dca54f 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "hash.h"
 #include "linklist.h"
index 4ea367ecad36bf5eac3fc4618ea043c322728dac..6f0faabc7361e1f932ffe335235500d6229606a3 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "if.h"
index 173ebdf20731817d08591fa51aaa1ec6a4462664..bc236406d6b7c7d6d48a68323314bc0ea863a07c 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "if.h"
index d3da5003aa9321cf030d63be682d3bd591ee68f9..c1f245d3beb227d76c3071c5f1b7e10ba75dd1bd 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "monotime.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "table.h"
 #include "vty.h"
index 5c3f184c5d1bd52551c24fd86dbc862bd74cc410..9ad1fca74f8cd7f059ba87d282f3fa747de4b54a 100644 (file)
@@ -14,7 +14,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "checksum.h"
index 05fc5c95d1ec47b0baf8278f6456a67e9880c7dc..7c591c0526b69aa1e88ea0f776d3d90f0156002b 100644 (file)
@@ -9,7 +9,7 @@
 #include <lib/version.h>
 #include "bfd.h"
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "linklist.h"
 #include "if.h"
index 8338c430772f2bec8ea248afd8501799faa7b621..d341b2dba187b1cd5222e1bd1f94bca0528422ef 100644 (file)
@@ -11,7 +11,7 @@
 #include "prefix.h"
 #include "memory.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "stream.h"
 #include "table.h"
 #include "log.h"
index e89ad020b18d6b4cdb8369d66ea9f6a0f69536a2..ba74e67a32ef77d6e1f89292318e2424db843424 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "if.h"
index 64bb454006f3b89dcdbe33de5f4097887125c9fa..57aa4925434e9196468da4341b6f814765a3a2da 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "hash.h"
 #include "linklist.h"
index fa04f092dcf6e538d182bd4b57b590185f100a27..0626f1060023071de2b309a9bb2d903a2a9e8ff4 100644 (file)
@@ -16,7 +16,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "printfrr.h"
index c4bccb3bc4f2f1c814e508014707159e319addc3..1462ad48f18273eac4eb2f681dd0c3d39ee54760 100644 (file)
@@ -7,7 +7,7 @@
 #include <zebra.h>
 
 #include "monotime.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "linklist.h"
 #include "prefix.h"
index a808ddc9f62aae4825fbae28906a51d8010324e1..2503f39a3c6af892d3cfd85775e9b69818ddb1a9 100644 (file)
@@ -20,7 +20,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "mpls.h"
index f731d1cf18060e24f8878973fbb906378a4b0dbe..272ef5ce0d064d9784005224dacb84d845ae8266 100644 (file)
@@ -6,7 +6,7 @@
 #include <zebra.h>
 
 #include "monotime.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "hash.h"
 #include "linklist.h"
index d1af08c652ce63a17edeaeae0a6802b6282a3a3e..00422e6b9ff1a314a0dc3b9dcb1e57df29e19ff0 100644 (file)
@@ -37,7 +37,7 @@
 #include "sockunion.h" /* for inet_aton() */
 #include "stream.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "zclient.h"
 #include "sbuf.h"
index e3869abe59104721156fdf47a196eba22cd078d0..2c4bd17d91342f53ec336beda244b4e997282fda 100644 (file)
@@ -24,7 +24,7 @@
 #include "vty.h"
 #include "stream.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
 #include "network.h"
index 262f805468d1c74b9fc98964ea6502983950dd4e..610422bd54df7d4ced62903c329f8212682b790c 100644 (file)
@@ -10,7 +10,7 @@
 #include "printfrr.h"
 #include "monotime.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "table.h"
 #include "vty.h"
index d321a69668723336607ca29c2bcf652b4d802a8d..67da49c21b2b1f0e06e2f1fd96cd415fee39002c 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "network.h"
 #include "prefix.h"
index 0296d9d9f58dddb84d51fc467ec83a6e45952cf6..c3edc9dd59fc434772d8f29801983ca9e5454919 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "linklist.h"
index 3d35b9f9b30ad579167ebc2b0c598973f0547808..7d54123d7fd21304f708a3e9ccebaa387b1a92ed 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "log.h"
 #include "memory.h"
index 21d127bcfe919fabd811263faaa1571480043abc..0e63b56f57bd2fba60e3ae92138db43cab5ee478 100644 (file)
@@ -13,7 +13,7 @@
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_config.h"
 #include "pathd/path_pcep_debug.h"
-#include "thread.h"
+#include "event.h"
 
 #define MAX_XPATH 256
 #define MAX_FLOAT_LEN 22
index efc016f750288c5d5ddabb0913f54290960c440e..28daac60bd97d1151e38dae2ec138e0fb123f589 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "lib_errors.h"
 #include "if.h"
index 9b34815c4db3a39ee7d5ef3a283ca478ae280049..2941dbeca7bd5618f9d9be3fdff3d39aad67a625 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "linklist.h"
 #include "if.h"
index 0e18f1198dfd78fd3ab1df17dda902cee65c5947..1519af4eef096c6538a0376bfba1aba6178a4d7f 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "table.h"
index 1b18853d2b87feb19342f58bb3cdec24e66db748..c2c785fb6bc20b2c6f582795ed1a96845ed7be50 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "network.h"
 #include "prefix.h"
index fa699cca5e7b7623707f43976c4d234db6f9c7b5..c722add848f802dea4015ce0657cf596807722ac 100644 (file)
@@ -19,7 +19,7 @@
 #include "lib/jhash.h"
 #include "lib/prefix.h"
 #include "lib/checksum.h"
-#include "lib/thread.h"
+#include "lib/event.h"
 #include "termtable.h"
 
 #include "pimd/pim6_mld.h"
index 136498beb713a5d9d5dd513da34f3cccd05275b6..98f594d0ca907e00a52f8509aea812a28c19632f 100644 (file)
@@ -7,7 +7,7 @@
 #include <zebra.h>
 
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "if.h"
 #include "vrf.h"
index ce4326c61697efa9f3017530067e042411456399..0a782455caec5138105def0435cfc17dd73c3497 100644 (file)
@@ -11,7 +11,7 @@
 #include "lib/version.h"
 #include <getopt.h>
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include <signal.h>
 
 #include "memory.h"
index 9d29a33a52a27a4f05e6d629bd575dc6974bf619..b3d30defe1586f94dd4807aa387276603a84b709 100644 (file)
@@ -12,7 +12,7 @@
 #include <lib/prefix.h>
 #include <lib/sockunion.h>
 #include <lib/stream.h>
-#include <lib/thread.h>
+#include <event.h>
 #include <lib/vty.h>
 #include <lib/plist.h>
 #include <lib/lib_errors.h>
index a6f318e61e60b2f4371b23018ad17a7a5fa46c86..c3dd0769674db4eed96b5a40df49a417fa64d73d 100644 (file)
@@ -8,7 +8,7 @@
 #include <lib/log.h>
 #include <lib/network.h>
 #include <lib/stream.h>
-#include <lib/thread.h>
+#include "event.h"
 #include <lib/vty.h>
 #include <lib/lib_errors.h>
 
index a6b5ee11b61ab83513ad2cb32cc3e0ed8b6f5e28..3bf6b1d74ba5c9679618b5c0257ed66fa96d6f1b 100644 (file)
@@ -9,7 +9,7 @@
 #include <lib/log.h>
 #include <lib/network.h>
 #include <lib/sockunion.h>
-#include <lib/thread.h>
+#include "event.h"
 #include <lib/vty.h>
 #include <lib/if.h>
 #include <lib/vrf.h>
index 1248db3de45f694d73f68b0531fb3763d430e8a0..697266e2b4b50252b5064294af539eb0659feb62 100644 (file)
@@ -7,7 +7,7 @@
 #include <zebra.h>
 
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "if.h"
 #include "network.h"
index 5144fe67b8e6e7fcedf51e9f6f6b78b2b0d24d48..42b013815a788fe03dd1388b8a1aa2a5b8ea4e99 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "log.h"
 #include "if.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "vty.h"
 #include "plist.h"
index c9555f5310cd361bd606b4e27bf7cae996633d1e..3f3d67f591f2a37b344931fb97ec15b2a612570e 100644 (file)
@@ -11,7 +11,7 @@
 #include <time.h>
 
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "lib_errors.h"
 
 #include "pim_time.h"
index fd1e79e2bbd21b77bfd7605f865c4f16f9d7a64f..a0707407e5c2ced210c41eff54fc8483182d7a4b 100644 (file)
@@ -10,7 +10,7 @@
 #include <stdint.h>
 
 #include <zebra.h>
-#include "thread.h"
+#include "event.h"
 
 int64_t pim_time_monotonic_sec(void);
 int64_t pim_time_monotonic_dsec(void);
index b0f11585961faeb8a22a82d4cb27114b78847168..1ee044197a7144883fc3ef366e15d065a58e2b32 100644 (file)
@@ -9,7 +9,7 @@
 #include "log.h"
 #include "zclient.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "linklist.h"
 #include "vty.h"
 #include "plist.h"
index 08807d0dcc993e8788acfb625bb113668a3bf7e8..5f574eb5b429a33d4e0182d0b6a18cc3cfe96182 100644 (file)
@@ -11,7 +11,7 @@
 #include "zclient.h"
 #include "stream.h"
 #include "network.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "vty.h"
 #include "lib_errors.h"
index b5873a3aac5b48e53bb735f9476e6609c5ad0c72..c325979d24f38d8d9a1313d3a434f12d97d02151 100644 (file)
@@ -44,7 +44,7 @@ daemon_flags = {
     "lib/routemap.c": "VTYSH_RMAP",
     "lib/routemap_cli.c": "VTYSH_RMAP",
     "lib/spf_backoff.c": "VTYSH_ISISD",
-    "lib/thread.c": "VTYSH_ALL",
+    "lib/event.c": "VTYSH_ALL",
     "lib/vrf.c": "VTYSH_VRF",
     "lib/vty.c": "VTYSH_ALL",
 }
index 3e62321725d0b760ffd5e96d369ccb5ece10b590..309c18f9c2f6f395ece48363001080ad4a6be269 100644 (file)
@@ -14,7 +14,7 @@
 #include "table.h"
 #include "log.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "zclient.h"
 #include "filter.h"
 #include "sockopt.h"
index e26424adeb63b0c275ebeb7339f569af9432e5f2..b6166b14c8b329e4ee3f51b2a3cfe8675a5b98c7 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "memory.h"
 #include "prefix.h"
index a3cba598d2fffc7a79519ca06122013a00c21aef..85cd971509f47f8bf6024c78eb3edca1e5abb371 100644 (file)
@@ -9,7 +9,7 @@
 #include "prefix.h"
 #include "command.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 
 #include "ripd/ripd.h"
index bde7e858f1255f9de42957959d56fbd08d7da62e..8b21af92ffa43448ff90c1f25b9fe26bb35d41ac 100644 (file)
@@ -11,7 +11,7 @@
 #include "command.h"
 #include "prefix.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "log.h"
 #include "stream.h"
index 1fc6f2553e358cd26da13df3add9ea47b3c53870..919f3c81d9cc724429e6d42a8221d605c5c8fe66 100644 (file)
@@ -17,7 +17,7 @@
 #include "zclient.h"
 #include "command.h"
 #include "agg_table.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "vrf.h"
 #include "lib_errors.h"
index 14e69834ca0ef78a0cc40f5bd93c3178363773eb..dcdd0c1f78aea17c86ea06a449857bf2ab264f4b 100644 (file)
@@ -12,7 +12,7 @@
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "log.h"
 #include "prefix.h"
 #include "if.h"
index 75a9ed77fee1be7e774d3807b8a11f80f909ce94..30b11aa143028253574857520bb01e9d19cd649c 100644 (file)
@@ -13,7 +13,7 @@
 #include "prefix.h"
 #include "command.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 
 #include "ripngd/ripngd.h"
index f01371f41ebb4a5b6df82600436b79abc6098bd8..24ff1bcd07ccd735407b683c29fd74451f2bb56f 100644 (file)
@@ -8,7 +8,7 @@
 #include "prefix.h"
 #include "filter.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "memory.h"
 #include "if.h"
 #include "stream.h"
index cadd818953b3c2b35d22daf75a75e50f165bf05c..9ef9b2d0f482073bc69ecd0afb7d9acb7ff39c8b 100644 (file)
@@ -11,7 +11,7 @@
 #include "prefix.h"
 #include "nexthop.h"
 #include "log.h"
-#include "thread.h"
+#include "event.h"
 #include "vrf.h"
 #include "zclient.h"
 #include "frr_pthread.h"
index 9d33fc89a7e081ed64870e863263da0dd05447b7..1895a49d8ec849e95f723c634670ece47706aed9 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "prefix.h"
 #include "linklist.h"
 #include "if.h"
index df06f5537e780e8b5f87c530c3e92220a6069e09..3c19435871ab977fe3e152ad3560b9adc1d19c1b 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "network.h"
 #include "prefix.h"
index d429162196c5c79579fec113473cb611764b6b7a..1d9b0d16cb40831c69fcecfd91a57fb7755a8a5a 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "log.h"
 #include "memory.h"
index f220b476fbbddbfae03a824813a03e48da188655..6c59f04ee620b30ad9285b1a04b693a9f1c6560f 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "network.h"
 #include "prefix.h"
index bb8acd2c44183aee09f5f8f536abea7a1b3d75ae..209b4ad86140efd0b2a27acdcf4b8721948973d9 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index 8f0b92d0fcd49b9173639f106217a29381e0f052..2443f3866f9f0070ef45230373fd9879004aa818 100644 (file)
@@ -9,7 +9,7 @@
 #include "memory.h"
 #include "sbuf.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_tlvs.h"
index 0cccf05678ef25b471a46d5117a334dd06a92411..37c22c5439ce397f227d868bfa90f5362e387656 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <lib/version.h>
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "log.h"
index 29dad7d80f61600459962fccd1961edbbda7e6b6..41703833892c744c2aa24ba94e4b19930b9233b5 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index 7aab88eeb98c639373705137c46ca8be412f3eb0..85dcea9e80378c66ee6173d9aa9fe485eaafebfe 100644 (file)
@@ -78,7 +78,7 @@
 #include "lib/stream.h"
 #include "lib/table.h"
 #include "lib/termtable.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/typesafe.h"
 #include "lib/typerb.h"
 #include "lib/vector.h"
index 3abda75f40fb829a0bb14203e2fd1eb4941c370f..b841fea25ef3040dbdd3fdce91aeb5ac5efb6db1 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index d68ee8a8191a2336fafe6e69e5b8b303172c7255..13f8daa5f3f671299cedf780ff193f090f7c327f 100644 (file)
@@ -22,7 +22,7 @@ static void func_for_bt(int number)
 
 #include <zebra.h>
 #include "lib/zlog.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/sigevent.h"
 
 int main(int argc, char **argv)
index 282161c3df8afe5955947c12362beb9b5d39b277..187b8091dfde7c6a12dc1683749a38666c0c7193 100644 (file)
@@ -14,7 +14,7 @@
 #include "libfrr.h"
 #include "routing_nb.h"
 #include "northbound_cli.h"
-#include "thread.h"
+#include "event.h"
 #include "vrf.h"
 #include "vty.h"
 
index 2d54fe6c68a564e619c03454fc6f34e908791832..7bce1584ec80cd37387c8ee1c995b5ec4a29df5d 100644 (file)
@@ -13,7 +13,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index afbd20545183d506f960be0f480fa8e607cc4a51..0cee1e863c0552276a6cc041f2c98de94577d94f 100644 (file)
@@ -14,7 +14,7 @@
 #include <zebra.h>
 #include <math.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index 9b2cfa5730d1d9f6e101bd2703608bb232e1ffa9..e09c4885c54fd03aed65f952daaed47ae7eaa782 100644 (file)
@@ -13,7 +13,7 @@
  */
 #include <zebra.h>
 
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "command.h"
 #include "memory.h"
index 015dc41db1edf3fd49be2f335a7ca90bd8966ca2..8bf6f7fcc199a326d05d93f75c4c799084c74d9d 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <zebra.h>
 #include <stream.h>
-#include <thread.h>
+#include "event.h"
 
 #include "printfrr.h"
 
index 37eb4939a1f78020460346b92f467455b2a4490f..fa197cd1c9a4822f7effff5f43120d4ea2ccc367 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "memory.h"
 #include "prng.h"
-#include "thread.h"
+#include "event.h"
 
 #define SCHEDULE_TIMERS 800
 #define REMOVE_TIMERS   200
index 21976e8d3100c55c38a7ace2abb66de419787b5a..5af0604d1b3503ac4d2587fb46ea5b5459700011 100644 (file)
@@ -14,7 +14,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#include "thread.h"
+#include "event.h"
 #include "prng.h"
 
 #define SCHEDULE_TIMERS 1000000
index b8a2aef69e122d80bcaea87b41f176fca5a54f34..d40b37b92775d4f1a1ebaf66ac48f7ba0e312ea2 100644 (file)
@@ -1,7 +1,7 @@
 #include <zebra.h>
 
 #include "getopt.h"
-#include "thread.h"
+#include "event.h"
 #include <lib/version.h>
 #include "vty.h"
 #include "command.h"
index 9da9c8a5182af10875e9b672c3314e52560189de..5cdba8677db571a48db52db007971a36c500d05f 100644 (file)
@@ -18,7 +18,7 @@
 #include "lib/northbound.h"
 #include "lib/privs.h"
 #include "lib/stream.h"
-#include "lib/thread.h"
+#include "lib/event.h"
 #include "lib/vty.h"
 
 /* Global definitions */
index d3d230d20508225cd8d1817e4de507a3bb64397f..90c3a77721880195e9c85308389a2f5d6ebd3415 100644 (file)
@@ -18,7 +18,7 @@
 #include "lib/nexthop.h"
 #include "lib/privs.h"
 #include "lib/sigevent.h"
-#include "lib/thread.h"
+#include "lib/event.h"
 #include "lib/vrf.h"
 #include "lib/vty.h"
 
index 84f4d02a8af4a164f7102a4aea672b63482d70c1..eb32cc96674014464a64fd38596a3d13ff69c583 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #include <zebra.h>
-#include <thread.h>
+#include "event.h"
 #include <log.h>
 #include <network.h>
 #include <sigevent.h>
index 21cad01374d438d819b4a6cf543bad8d81c0853e..8fb5b28c3d9f146835b13b561f82f6b4e6a6b2ed 100644 (file)
@@ -33,7 +33,7 @@
 #include "table.h"
 #include "memory.h"
 #include "rib.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "nexthop.h"
 #include "vrf.h"
index 0c9b6f3d3965eb758b04be459abc2ca6ba38785d..28d6b89ed4e13e7b0bc24e41cd01e2b598567745 100644 (file)
@@ -24,7 +24,7 @@
 #include "connected.h"
 #include "log.h"
 #include "zclient.h"
-#include "thread.h"
+#include "event.h"
 #include "lib_errors.h"
 #include "zebra/interface.h"
 #include "zebra/rtadv.h"
index ddcad92bdc7bb7c16107a4039fca8b0b6cb7234f..8940970208b6f597cd26d223058aa8307bc17a85 100644 (file)
@@ -32,7 +32,7 @@
 #include "connected.h"
 #include "log.h"
 #include "zclient.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "libfrr.h"
 #include "lib_errors.h"
index 4f4f3772dc806b9e45477664770fab61e0bf08bb..7903f14e1a71088059fe48e62cd9e17036f5b305 100644 (file)
@@ -34,7 +34,7 @@
 #include "sockunion.h"
 #include "sockunion.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "vty.h"
 #include "zclient.h"
 #include "lib_errors.h"
index a980b56b33845375c4a7ec74d598f643ac121ec1..fdf4b850d3c42fe104eacf7e83c4b68b7a44ca28 100644 (file)
@@ -15,7 +15,7 @@
 #include "table.h"
 #include "memory.h"
 #include "rib.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "nexthop.h"
 #include "vrf.h"
index 915fd087fed2b79ed89f55aa0fc202c0c4a7afa1..04f484cd9a5206a0dde0c185387e76210c2ae6e7 100644 (file)
@@ -1255,7 +1255,7 @@ int rtm_write(int message, union sockunion *dest, union sockunion *mask,
 }
 
 
-#include "thread.h"
+#include "event.h"
 #include "zebra/zserv.h"
 
 /* For debug purpose. */
index c0bd8e369fa7d28b2b850af59bfa93d9f020ea4a..e2f5d19019d3aaf2e48fea6441f7fe9d18a676fe 100644 (file)
@@ -14,7 +14,7 @@
 #include <stdint.h>
 
 #include "lib/linklist.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/hook.h"
 
 #include "zebra/zserv.h"
index c40a03551d501f39e7eefc794e2932f55a43b057..49b928d09cb6b430aaeed8879aa6575c16045d7e 100644 (file)
@@ -8,7 +8,7 @@
 #include <lib/version.h>
 #include "getopt.h"
 #include "command.h"
-#include "thread.h"
+#include "event.h"
 #include "filter.h"
 #include "memory.h"
 #include "prefix.h"
index e4ddbd95d7767a4ce38872296b69102e519f2b66..e92fb19151560eb3cbe7bb1331d817c5daa99f5c 100644 (file)
@@ -38,7 +38,7 @@
 #include "table.h"
 #include "memory.h"
 #include "rib.h"
-#include "thread.h"
+#include "event.h"
 #include "privs.h"
 #include "nexthop.h"
 #include "vrf.h"
index 1e0769fb6d742ce6964d070b584183b04054299c..7f9a8ed00cc4de33ca15719d4194753101bf441e 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "memory.h"
 #include "sockopt.h"
-#include "thread.h"
+#include "event.h"
 #include "if.h"
 #include "stream.h"
 #include "log.h"
index deed4fa30b5c997c0f53c50f691ba17d520f6cd7..eb460c291f42b6f0ef320f38600df53f8c6b3735 100644 (file)
@@ -9,7 +9,7 @@
 #include <stdint.h>
 
 #include "lib/linklist.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/ns.h"
 
 #include "zebra/zserv.h"
index 15765b5e185741a1c3a4b8a2378fe4a7495f1a25..f7de5eb0c60259ee1cfab74cd5a0fe378abc7757 100644 (file)
@@ -11,7 +11,7 @@
 #include "log.h"
 #include "libfrr.h"
 #include "stream.h"
-#include "thread.h"
+#include "event.h"
 #include "network.h"
 #include "command.h"
 #include "lib/version.h"
index 3724ea090186c853f6a9b2bcf0a8dbefc49c0850..c9881e51dc3917184077176c6563e04740c46927 100644 (file)
@@ -13,7 +13,7 @@
 #include "lib/prefix.h"
 #include "lib/command.h"
 #include "lib/if.h"
-#include "lib/thread.h"
+#include "event.h"
 #include "lib/stream.h"
 #include "lib/memory.h"
 #include "lib/table.h"
index 334eb6dc469583e9735ea236aaa71b879393045a..d9189206fa325e6af24f22e4bd57bc6f51856771 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "hook.h"
 #include "module.h"
-#include "thread.h"
+#include "event.h"
 #include "frr_pthread.h"
 #include "libfrr.h"
 #include "lib/version.h"
index 4aaf6f25afdd6c23e3af2e6869f56f7e6695fde3..dfb4875ffcdb16072fe46128667cf65da2fc91fe 100644 (file)
@@ -13,7 +13,7 @@
 #include "log.h"
 #include "sockunion.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "workqueue.h"
 #include "prefix.h"
 #include "routemap.h"
index 28f3c03abea845c63343bebf1a3fe75e2b3f8000..468acbdfe417c91a051ee28144b438f8eb9e8dba 100644 (file)
@@ -17,7 +17,7 @@
 #include <sys/inotify.h>
 #include <sys/stat.h>
 
-#include "thread.h"
+#include "event.h"
 #include "ns.h"
 #include "command.h"
 #include "memory.h"
index dc56ba3c3042d4416911c57337b0183671d74802..a3f7ba62808163089f3dcfedd64cffdc072a2481 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "log.h"
 #include "memory.h"
-#include "thread.h"
+#include "event.h"
 #include "command.h"
 #include "vrf.h"
 #include "lib/json.h"
index 6c499b77d70adcdec329dcb2a53f84688c487e10..5e9eda168ecf3c69bc1f8e2e9665db5e14177fbe 100644 (file)
@@ -18,7 +18,7 @@
 #include "sockunion.h"
 #include "srcdest_table.h"
 #include "table.h"
-#include "thread.h"
+#include "event.h"
 #include "vrf.h"
 #include "workqueue.h"
 #include "nexthop_group_private.h"
index 2666dc232f08093513002b3489e7b89c40295f67..61a4559e04fb0612fb6b210f4dbfca6e95519a83 100644 (file)
@@ -13,7 +13,7 @@
 #include "log.h"
 #include "sockunion.h"
 #include "linklist.h"
-#include "thread.h"
+#include "event.h"
 #include "workqueue.h"
 #include "prefix.h"
 #include "routemap.h"
index e064c27ad17253f8722fb7bbb39bbf97bf731d55..3563068a66b1b6465587e8228288cf6eedbdfd4c 100644 (file)
@@ -34,7 +34,7 @@
 #include "lib/sockopt.h"          /* for setsockopt_so_recvbuf, setsockopt... */
 #include "lib/sockunion.h"        /* for sockopt_reuseaddr, sockopt_reuseport */
 #include "lib/stream.h"           /* for STREAM_SIZE, stream (ptr only), ... */
-#include "lib/thread.h"           /* for thread (ptr only), THREAD_ARG, ... */
+#include "event.h"                /* for thread (ptr only), THREAD_ARG, ... */
 #include "lib/vrf.h"              /* for vrf_info_lookup, VRF_DEFAULT */
 #include "lib/vty.h"              /* for vty_out, vty (ptr only) */
 #include "lib/zclient.h"          /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
index 1226cd7115b2a20ca8f360d544eb5cdc053a263f..0faea9dd7300a613f0f31123fd20d4afde6f4890 100644 (file)
@@ -19,7 +19,7 @@
 #include "lib/vrf.h"          /* for vrf_bitmap_t */
 #include "lib/zclient.h"      /* for redist_proto */
 #include "lib/stream.h"       /* for stream, stream_fifo */
-#include "lib/thread.h"       /* for thread, thread_master */
+#include "event.h"            /* for thread, thread_master */
 #include "lib/linklist.h"     /* for list */
 #include "lib/workqueue.h"    /* for work_queue */
 #include "lib/hook.h"         /* for DECLARE_HOOK, DECLARE_KOOH */