]> git.proxmox.com Git - mirror_frr.git/blob - tests/lib/test_heavy_wq.c
*: make consistent & update GPLv2 file headers
[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 along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /* This programme shows the effects of 'heavy' long-running functions
20 * on the cooperative threading model.
21 *
22 * Run it with a config file containing 'password whatever', telnet to it
23 * (it defaults to port 4000) and enter the 'clear foo string' command.
24 * then type whatever and observe that the vty interface is unresponsive
25 * for quite a period of time, due to the clear_something command
26 * taking a very long time to complete.
27 */
28 #include <zebra.h>
29
30 #include "thread.h"
31 #include "vty.h"
32 #include "command.h"
33 #include "memory.h"
34 #include "log.h"
35 #include "workqueue.h"
36 #include <math.h>
37
38 #include "tests.h"
39
40 DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test")
41 DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node")
42 DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str")
43
44 extern struct thread_master *master;
45 static struct work_queue *heavy_wq;
46
47 struct heavy_wq_node
48 {
49 char *str;
50 int i;
51 };
52
53 enum
54 {
55 ITERS_FIRST = 0,
56 ITERS_ERR = 100,
57 ITERS_LATER = 400,
58 ITERS_PRINT = 10,
59 ITERS_MAX = 1000,
60 };
61
62 static void
63 heavy_wq_add (struct vty *vty, const char *str, int i)
64 {
65 struct heavy_wq_node *hn;
66
67 if ((hn = XCALLOC (MTYPE_WQ_NODE, sizeof(struct heavy_wq_node))) == NULL)
68 {
69 zlog_err ("%s: unable to allocate hn", __func__);
70 return;
71 }
72
73 hn->i = i;
74 if (!(hn->str = XSTRDUP (MTYPE_WQ_NODE_STR, str)))
75 {
76 zlog_err ("%s: unable to xstrdup", __func__);
77 XFREE (MTYPE_WQ_NODE, hn);
78 return;
79 }
80
81 work_queue_add (heavy_wq, hn);
82
83 return;
84 }
85
86 static void
87 slow_func_err (struct work_queue *wq, struct work_queue_item *item)
88 {
89 printf ("%s: running error function\n", __func__);
90 }
91
92 static void
93 slow_func_del (struct work_queue *wq, void *data)
94 {
95 struct heavy_wq_node *hn = data;
96 assert (hn && hn->str);
97 printf ("%s: %s\n", __func__, hn->str);
98 XFREE (MTYPE_WQ_NODE_STR, hn->str);
99 hn->str = NULL;
100 XFREE(MTYPE_WQ_NODE, hn);
101 }
102
103 static wq_item_status
104 slow_func (struct work_queue *wq, void *data)
105 {
106 struct heavy_wq_node *hn = data;
107 double x = 1;
108 int j;
109
110 assert (hn && hn->str);
111
112 for (j = 0; j < 300; j++)
113 x += sin(x)*j;
114
115 if ((hn->i % ITERS_LATER) == 0)
116 return WQ_RETRY_LATER;
117
118 if ((hn->i % ITERS_ERR) == 0)
119 return WQ_RETRY_NOW;
120
121 if ((hn->i % ITERS_PRINT) == 0)
122 printf ("%s did %d, x = %g\n", hn->str, hn->i, x);
123
124 return WQ_SUCCESS;
125 }
126
127 static void
128 clear_something (struct vty *vty, const char *str)
129 {
130 int i;
131
132 /* this could be like iterating through 150k of route_table
133 * or worse, iterating through a list of peers, to bgp_stop them with
134 * each having 150k route tables to process...
135 */
136 for (i = ITERS_FIRST; i < ITERS_MAX; i++)
137 heavy_wq_add (vty, str, i);
138 }
139
140 DEFUN (clear_foo,
141 clear_foo_cmd,
142 "clear foo LINE...",
143 "clear command\n"
144 "arbitrary string\n")
145 {
146 char *str;
147 if (!argc)
148 {
149 vty_out (vty, "%% string argument required%s", VTY_NEWLINE);
150 return CMD_WARNING;
151 }
152
153 str = argv_concat (argv, argc, 0);
154
155 clear_something (vty, str);
156 XFREE (MTYPE_TMP, str);
157 return CMD_SUCCESS;
158 }
159
160 static int
161 heavy_wq_init ()
162 {
163 if (! (heavy_wq = work_queue_new (master, "heavy_work_queue")))
164 {
165 zlog_err ("%s: could not get new work queue!", __func__);
166 return -1;
167 }
168
169 heavy_wq->spec.workfunc = &slow_func;
170 heavy_wq->spec.errorfunc = &slow_func_err;
171 heavy_wq->spec.del_item_data = &slow_func_del;
172 heavy_wq->spec.max_retries = 3;
173 heavy_wq->spec.hold = 1000;
174
175 return 0;
176 }
177
178 void
179 test_init()
180 {
181 install_element (VIEW_NODE, &clear_foo_cmd);
182 heavy_wq_init();
183 }