Import Upstream version 1.2.2
[quagga-debian.git] / tests / heavy-thread.c
1 /*
2  * $Id: heavy-thread.c,v 1.2 2005/04/25 16:42:24 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 "thread.h"
35 #include "vty.h"
36 #include "command.h"
37 #include "memory.h"
38 #include "log.h"
39
40 #include "tests.h"
41
42 extern struct thread_master *master;
43
44 enum
45 {
46   ITERS_FIRST = 0,
47   ITERS_ERR = 100,
48   ITERS_LATER = 400,
49   ITERS_PRINT = 10,
50   ITERS_MAX = 1000,
51 };
52
53 struct work_state {
54   struct vty *vty;
55   char *str;
56   int i;
57 };
58
59 static void
60 slow_func (struct vty *vty, const char *str, const int i)
61 {
62   double x = 1;
63   int j;
64   
65   for (j = 0; j < 300; j++)
66     x += sin(x)*j;
67   
68   if ((i % ITERS_LATER) == 0)
69     printf ("%s: %d, temporary error, save this somehow and do it later..\n",
70             __func__, i);
71   
72   if ((i % ITERS_ERR) == 0)
73     printf ("%s: hard error\n", __func__);
74   
75   if ((i % ITERS_PRINT) == 0)
76     printf ("%s did %d, x = %g\n", str, i, x);
77 }
78
79 static int
80 clear_something (struct thread *thread)
81 {
82   struct work_state *ws = THREAD_ARG(thread);
83   
84   /* this could be like iterating through 150k of route_table 
85    * or worse, iterating through a list of peers, to bgp_stop them with
86    * each having 150k route tables to process...
87    */
88   while (ws->i < ITERS_MAX)
89     {
90       slow_func(ws->vty, ws->str, ws->i);
91       ws->i++;
92       if (thread_should_yield(thread))
93         {
94           thread_add_background(master, clear_something, ws, 0);
95           return 0;
96         }
97     }
98   
99   /* All done! */
100   XFREE (MTYPE_TMP, ws->str);
101   XFREE (MTYPE_TMP, ws);
102   return 0;
103 }
104
105 DEFUN (clear_foo,
106        clear_foo_cmd,
107        "clear foo .LINE",
108        "clear command\n"
109        "arbitrary string\n")
110 {
111   char *str;
112   struct work_state *ws;
113
114   if (!argc)
115     {
116       vty_out (vty, "%% string argument required%s", VTY_NEWLINE);
117       return CMD_WARNING;
118     }
119   
120   str = argv_concat (argv, argc, 0);
121   
122   if ((ws = XMALLOC(MTYPE_TMP, sizeof(*ws))) == NULL)
123     {
124       zlog_err ("%s: unable to allocate work_state", __func__);
125       return CMD_WARNING;
126     }
127   
128   if (!(ws->str = XSTRDUP (MTYPE_TMP, str)))
129     {
130       zlog_err ("%s: unable to xstrdup", __func__);
131       XFREE (MTYPE_TMP, ws);
132       return CMD_WARNING;
133     }
134   
135   ws->vty = vty;
136   ws->i = ITERS_FIRST;
137
138   thread_add_background(master, clear_something, ws, 0);
139
140   return CMD_SUCCESS;
141 }
142
143 void
144 test_init()
145 {
146   install_element (VIEW_NODE, &clear_foo_cmd);
147 }