]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/test_heavy_wq.c
release: FRR 3.0-rc1
[mirror_frr.git] / tests / lib / test_heavy_wq.c
1 /*
2 * This file is part of Quagga.
3 *
4 * Quagga is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2, or (at your option) any
7 * later version.
8 *
9 * Quagga is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Quagga; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 */
19
20 /* This programme shows the effects of 'heavy' long-running functions
21 * on the cooperative threading model.
22 *
23 * Run it with a config file containing 'password whatever', telnet to it
24 * (it defaults to port 4000) and enter the 'clear foo string' command.
25 * then type whatever and observe that the vty interface is unresponsive
26 * for quite a period of time, due to the clear_something command
27 * taking a very long time to complete.
28 */
29 #include <zebra.h>
30
31 #include "thread.h"
32 #include "vty.h"
33 #include "command.h"
34 #include "memory.h"
35 #include "log.h"
36 #include "workqueue.h"
37 #include <math.h>
38
39 #include "tests.h"
40
41 DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test")
42 DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node")
43 DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str")
44
45 extern struct thread_master *master;
46 static struct work_queue *heavy_wq;
47
48 struct heavy_wq_node {
49 char *str;
50 int i;
51 };
52
53 enum { ITERS_FIRST = 0,
54 ITERS_ERR = 100,
55 ITERS_LATER = 400,
56 ITERS_PRINT = 10,
57 ITERS_MAX = 1000,
58 };
59
60 static void heavy_wq_add(struct vty *vty, const char *str, int i)
61 {
62 struct heavy_wq_node *hn;
63
64 if ((hn = XCALLOC(MTYPE_WQ_NODE, sizeof(struct heavy_wq_node)))
65 == NULL) {
66 zlog_err("%s: unable to allocate hn", __func__);
67 return;
68 }
69
70 hn->i = i;
71 if (!(hn->str = XSTRDUP(MTYPE_WQ_NODE_STR, str))) {
72 zlog_err("%s: unable to xstrdup", __func__);
73 XFREE(MTYPE_WQ_NODE, hn);
74 return;
75 }
76
77 work_queue_add(heavy_wq, hn);
78
79 return;
80 }
81
82 static void slow_func_err(struct work_queue *wq, struct work_queue_item *item)
83 {
84 printf("%s: running error function\n", __func__);
85 }
86
87 static void slow_func_del(struct work_queue *wq, void *data)
88 {
89 struct heavy_wq_node *hn = data;
90 assert(hn && hn->str);
91 printf("%s: %s\n", __func__, hn->str);
92 XFREE(MTYPE_WQ_NODE_STR, hn->str);
93 hn->str = NULL;
94 XFREE(MTYPE_WQ_NODE, hn);
95 }
96
97 static wq_item_status slow_func(struct work_queue *wq, void *data)
98 {
99 struct heavy_wq_node *hn = data;
100 double x = 1;
101 int j;
102
103 assert(hn && hn->str);
104
105 for (j = 0; j < 300; j++)
106 x += sin(x) * j;
107
108 if ((hn->i % ITERS_LATER) == 0)
109 return WQ_RETRY_LATER;
110
111 if ((hn->i % ITERS_ERR) == 0)
112 return WQ_RETRY_NOW;
113
114 if ((hn->i % ITERS_PRINT) == 0)
115 printf("%s did %d, x = %g\n", hn->str, hn->i, x);
116
117 return WQ_SUCCESS;
118 }
119
120 static void clear_something(struct vty *vty, const char *str)
121 {
122 int i;
123
124 /* this could be like iterating through 150k of route_table
125 * or worse, iterating through a list of peers, to bgp_stop them with
126 * each having 150k route tables to process...
127 */
128 for (i = ITERS_FIRST; i < ITERS_MAX; i++)
129 heavy_wq_add(vty, str, i);
130 }
131
132 DEFUN (clear_foo,
133 clear_foo_cmd,
134 "clear foo LINE...",
135 "clear command\n"
136 "arbitrary string\n")
137 {
138 char *str;
139 if (!argc) {
140 vty_out(vty, "%% string argument required%s", VTY_NEWLINE);
141 return CMD_WARNING;
142 }
143
144 str = argv_concat(argv, argc, 0);
145
146 clear_something(vty, str);
147 XFREE(MTYPE_TMP, str);
148 return CMD_SUCCESS;
149 }
150
151 static int heavy_wq_init()
152 {
153 if (!(heavy_wq = work_queue_new(master, "heavy_work_queue"))) {
154 zlog_err("%s: could not get new work queue!", __func__);
155 return -1;
156 }
157
158 heavy_wq->spec.workfunc = &slow_func;
159 heavy_wq->spec.errorfunc = &slow_func_err;
160 heavy_wq->spec.del_item_data = &slow_func_del;
161 heavy_wq->spec.max_retries = 3;
162 heavy_wq->spec.hold = 1000;
163
164 return 0;
165 }
166
167 void test_init()
168 {
169 install_element(VIEW_NODE, &clear_foo_cmd);
170 heavy_wq_init();
171 }