blob: 252c29607030b99881c46bedde11c58c6400d1b5 [file] [log] [blame]
paul864c3642005-04-22 00:50:08 +00001/*
2 * $Id: heavy-thread.c,v 1.1 2005/04/22 00:50:08 paul Exp $
3 *
4 * This file is part of Quagga.
5 *
6 * Quagga is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * Quagga is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Quagga; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22/* This programme shows the effects of 'heavy' long-running functions
23 * on the cooperative threading model, as demonstrated by heavy.c, and how
24 * they can be mitigated using a background thread.
25 *
26 * Run it with a config file containing 'password whatever', telnet to it
27 * (it defaults to port 4000) and enter the 'clear foo string' command.
28 * then type whatever and observe that, unlike heavy.c, the vty interface
29 * remains responsive.
30 */
31#include <zebra.h>
32#include <math.h>
33
34#include <lib/version.h>
35#include "getopt.h"
36#include "thread.h"
37#include "vty.h"
38#include "command.h"
39#include "memory.h"
40#include "log.h"
41
42struct thread_master *master;
43
44struct option longopts[] =
45{
46 { "daemon", no_argument, NULL, 'd'},
47 { "config_file", required_argument, NULL, 'f'},
48 { "help", no_argument, NULL, 'h'},
49 { "vty_addr", required_argument, NULL, 'A'},
50 { "vty_port", required_argument, NULL, 'P'},
51 { "version", no_argument, NULL, 'v'},
52 { 0 }
53};
54
55enum
56{
57 ITERS_FIRST = 0,
58 ITERS_ERR = 100,
59 ITERS_LATER = 400,
60 ITERS_PRINT = 10,
61 ITERS_MAX = 1000,
62};
63
64struct work_state {
65 struct vty *vty;
66 char *str;
67 int i;
68};
69
70static void
71slow_func (struct vty *vty, const char *str, const int i)
72{
73 double x = 1;
74 int j;
75
76 for (j = 0; j < 30000; j++)
77 x += sin(x)*j;
78
79 if ((i % ITERS_LATER) == 0)
80 printf ("%s: %d, temporary error, save this somehow and do it later..\n",
81 __func__, i);
82
83 if ((i % ITERS_ERR) == 0)
84 printf ("%s: hard error\n", __func__);
85
86 if ((i % ITERS_PRINT) == 0)
87 printf ("%s did %d, x = %g\n", str, i, x);
88}
89
90static int
91clear_something (struct thread *thread)
92{
93 struct work_state *ws = THREAD_ARG(thread);
94
95 /* this could be like iterating through 150k of route_table
96 * or worse, iterating through a list of peers, to bgp_stop them with
97 * each having 150k route tables to process...
98 */
99 while (ws->i < ITERS_MAX)
100 {
101 slow_func(ws->vty, ws->str, ws->i);
102 ws->i++;
103 if (thread_should_yield(thread))
104 {
105 thread_add_background(master, clear_something, ws, 0);
106 return 0;
107 }
108 }
109
110 /* All done! */
111 XFREE (MTYPE_TMP, ws->str);
112 XFREE (MTYPE_TMP, ws);
113 return 0;
114}
115
116DEFUN (daemon_exit,
117 daemon_exit_cmd,
118 "daemon-exit",
119 "Make the daemon exit\n")
120{
121 exit(0);
122}
123
124DEFUN (clear_foo,
125 clear_foo_cmd,
126 "clear foo .LINE",
127 "clear command\n"
128 "arbitrary string\n")
129{
130 char *str;
131 struct work_state *ws;
132
133 if (!argc)
134 {
135 vty_out (vty, "%% string argument required%s", VTY_NEWLINE);
136 return CMD_WARNING;
137 }
138
139 str = argv_concat (argv, argc, 0);
140
141 if ((ws = XMALLOC(MTYPE_TMP, sizeof(*ws))) == NULL)
142 {
143 zlog_err ("%s: unable to allocate work_state", __func__);
144 return CMD_WARNING;
145 }
146
147 if (!(ws->str = XSTRDUP (MTYPE_TMP, str)))
148 {
149 zlog_err ("%s: unable to xstrdup", __func__);
150 XFREE (MTYPE_TMP, ws);
151 return CMD_WARNING;
152 }
153
154 ws->vty = vty;
155 ws->i = ITERS_FIRST;
156
157 thread_add_background(master, clear_something, ws, 0);
158
159 return CMD_SUCCESS;
160}
161
162static int timer_count;
163int
164heavy_timer (struct thread *thread)
165{
166 int *count = THREAD_ARG(thread);
167
168 printf ("run %d of timer\n", (*count)++);
169 thread_add_timer (master, heavy_timer, count, 5);
170 return 0;
171}
172
173static void
174heavy_timer_init()
175{
176 thread_add_timer (master, heavy_timer, &timer_count, 5);
177}
178
179static void
180slow_vty_init()
181{
182 install_element (VIEW_NODE, &clear_foo_cmd);
183 install_element (VIEW_NODE, &daemon_exit_cmd);
184}
185
186/* Help information display. */
187static void
188usage (char *progname, int status)
189{
190 if (status != 0)
191 fprintf (stderr, "Try `%s --help' for more information.\n", progname);
192 else
193 {
194 printf ("Usage : %s [OPTION...]\n\
195Daemon which does 'slow' things.\n\n\
196-d, --daemon Runs in daemon mode\n\
197-f, --config_file Set configuration file name\n\
198-A, --vty_addr Set vty's bind address\n\
199-P, --vty_port Set vty's port number\n\
200-v, --version Print program version\n\
201-h, --help Display this help and exit\n\
202\n\
203Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
204 }
205 exit (status);
206}
207
208
209/* main routine. */
210int
211main (int argc, char **argv)
212{
213 char *p;
214 char *vty_addr = NULL;
215 int vty_port = 4000;
216 int daemon_mode = 0;
217 char *progname;
218 struct thread thread;
219 char *config_file = NULL;
220
221 /* Set umask before anything for security */
222 umask (0027);
223
224 /* get program name */
225 progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
226
227 /* master init. */
228 master = thread_master_create ();
229
230 while (1)
231 {
232 int opt;
233
234 opt = getopt_long (argc, argv, "dhf:A:P:v", longopts, 0);
235
236 if (opt == EOF)
237 break;
238
239 switch (opt)
240 {
241 case 0:
242 break;
243 case 'f':
244 config_file = optarg;
245 break;
246 case 'd':
247 daemon_mode = 1;
248 break;
249 case 'A':
250 vty_addr = optarg;
251 break;
252 case 'P':
253 /* Deal with atoi() returning 0 on failure */
254 if (strcmp(optarg, "0") == 0)
255 {
256 vty_port = 0;
257 break;
258 }
259 vty_port = atoi (optarg);
260 vty_port = (vty_port ? vty_port : 4000);
261 break;
262 case 'v':
263 print_version (progname);
264 exit (0);
265 break;
266 case 'h':
267 usage (progname, 0);
268 break;
269 default:
270 usage (progname, 1);
271 break;
272 }
273 }
274
275 /* Library inits. */
276 cmd_init (1);
277 vty_init (master);
278 memory_init ();
279
280 /* OSPF vty inits. */
281 slow_vty_init ();
282
283 sort_node ();
284
285 /* Change to the daemon program. */
286 if (daemon_mode)
287 daemon (0, 0);
288
289 /* Create VTY socket */
290 vty_serv_sock (vty_addr, vty_port, "/tmp/.heavy.sock");
291
292 /* Configuration file read*/
293 if (!config_file)
294 usage (progname, 1);
295 vty_read_config (config_file, NULL);
296
297 heavy_timer_init();
298
299 /* Fetch next active thread. */
300 while (thread_fetch (master, &thread))
301 thread_call (&thread);
302
303 /* Not reached. */
304 exit (0);
305}
306