summaryrefslogtreecommitdiffstats
path: root/exim_monitor/em_strip.c
blob: 03864d2908b2dcc84b1bf8fbe392d65d915f252b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*************************************************
*                   Exim Monitor                 *
*************************************************/

/* Copyright (c) University of Cambridge 1995 - 2009 */
/* See the file NOTICE for conditions of use and distribution. */


#include "em_hdr.h"

/* This module contains functions for handling stripcharts */


/*************************************************
*               Static variables                 *
*************************************************/

static int     queue_first_time = 1;         /* flag for resetting time */
static int     size_first_time = 1;          /* and another */

static int     stripchart_count = 0;         /* count stripcharts created */
static int    *stripchart_delay;             /* vector of delay counts */
static Widget *stripchart_label;             /* vector of label widgets */
static int    *stripchart_last_total;        /* vector of previous values */
static int    *stripchart_max;               /* vector of maxima */
static int    *stripchart_middelay;          /* vector of */
static int    *stripchart_midmax;            /* vector of */
static uschar  **stripchart_name;              /* vector of name strings */
static Widget  stripchart_prev_chart = NULL; /* previously created chart */
static Widget  stripchart_prev_label = NULL; /* previously created label */



/*************************************************
*               Initialize                       *
*************************************************/

void stripchart_init(void)
{
stripchart_delay =      (int *)store_malloc(stripchart_number * sizeof(int));
stripchart_label =   (Widget *)store_malloc(stripchart_number * sizeof(Widget));
stripchart_last_total = (int *)store_malloc(stripchart_number * sizeof(int));
stripchart_max =        (int *)store_malloc(stripchart_number * sizeof(int));
stripchart_middelay =   (int *)store_malloc(stripchart_number * sizeof(int));
stripchart_midmax =     (int *)store_malloc(stripchart_number * sizeof(int));
stripchart_name =     (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
stripchart_total =      (int *)store_malloc(stripchart_number * sizeof(int));
}



/*************************************************
*           Stripchart callback function         *
*************************************************/

/* The client data is the index of the stripchart. We have to play
a little game in order to ensure that the double value is correctly
passed back via the value pointer without the compiler doing an
unwanted cast. */

static void
stripchartAction(Widget w, XtPointer client_data, XtPointer value)
{
double * ptr = (double *)value;
static int thresholds[] =
  {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 0};
int num = (long)client_data;
int oldmax = 0;
int newmax = 0;
int newvalue = 0;
int i = 0;

/* For the queue stripchart, the value is the current vector value.
We reset the initial delay of 1 second to the normal value. */

if (num == 0)
  {
  newvalue = stripchart_total[0];
  if (queue_first_time)
    {
    xs_SetValues(w, 1, "update", stripchart_update);
    queue_first_time = 0;
    }
  }

/* For the size monitoring stripchart, the value is the percentage
fullness of the partition. A similar fudge to the above is implemented
for the first time. Not all OS have statvfs(); for those that don't this
code is omitted. In fact it should never be obeyed, as we don't allow
size_stripchart to get set in that case. For some OS the old function
and struct name statfs is used; that is handled by a macro. */

else if (size_stripchart != NULL && num == 1)
  {
#ifdef HAVE_STATFS
  struct statvfs statbuf;
  if (statvfs(CS size_stripchart, &statbuf) == 0)
    {
    int used = statbuf.f_blocks - statbuf.f_bfree;
    int max = used + statbuf.f_bavail;
    double fraction = ((double)used) / ((double)max);
    newvalue = (int)((fraction + 0.005) * 100.0);
    }
#endif
  if (size_first_time)
    {
    xs_SetValues(w, 1, "update", stripchart_update);
    size_first_time = 0;
    }
  }

/* For the configured stripcharts, the value to be set is
the difference from last time; save the current total for
next time. */

else
  {
  newvalue = stripchart_total[num] - stripchart_last_total[num];
  stripchart_last_total[num] = stripchart_total[num];
  }

/* Adjust the scale of the stripchart according to the value;
we delay enlarging the scale for a while after the values
reduce. Keep the maximum value while delaying, and reset
down to that. For the size stripchart, the threshold is always
forced to be at least 100. */

while (thresholds[i] > 0)
  {
  int thresh = (size_stripchart != NULL && num == 1)? 100 : thresholds[i++];
  if (newvalue < (double)thresh)
    {
    /* If the current maximum is less than required, or if it is
    greater and we have delayed long enough, adjust the scale. */

    if (stripchart_max[num] < thresh ||
       (stripchart_max[num] > thresh && stripchart_delay[num]++ > 20))
      {
      uschar buffer[128];
      newmax = (thresh > stripchart_midmax[num])?
        thresh : stripchart_midmax[num];
      if (newmax == 10) sprintf(CS buffer, "%s", stripchart_name[num]);
        else sprintf(CS buffer, "%s x%d", stripchart_name[num], newmax/10);
      if (size_stripchart != NULL && num == 1) Ustrcat(buffer, US"%");
      xs_SetValues(stripchart_label[num], 1, "label", buffer);
      oldmax = stripchart_max[num];
      stripchart_max[num] = newmax;
      stripchart_midmax[num] = 0;
      stripchart_delay[num] -= stripchart_middelay[num];
      }

    /* Otherwise, if the current maximum is greater than required,
    keep the highest value encountered during the delay, and its
    position so we can adjust the delay when re-scaling. */

    else if (stripchart_max[num] > thresh)
      {
      if (thresh > stripchart_midmax[num])
        {
        stripchart_midmax[num] = thresh;
        stripchart_middelay[num] = stripchart_delay[num];
        }
      }

    /* If the maximum is exactly what we need, reset the delay. */

    if (stripchart_max[num] == thresh) stripchart_delay[num] = 0;
    break;
    }
  }

/* The vanilla Athena stripchart widget does not support change of
scale - it just draws scale lines closer and closer together, which
doesn't work when the number gets very large. However, we can cause
it to change scale quite simply by recomputing all the values and
then calling its repaint routine. I had to nobble the repaint routine
too, to stop it changing scale to anything other than 10. There's
probably a better way to do this, like adding some new resource, but
I'm not a widget programmer and want to get on with the rest of
eximon... */

if (oldmax > 0)
  {
  int i;
  StripChartWidget ww = (StripChartWidget)w;
  ww->strip_chart.max_value = 0;
  for (i = 0; i < (int)ww->strip_chart.interval; i++)
    {
    ww->strip_chart.valuedata[i] =
      (ww->strip_chart.valuedata[i] * oldmax)/newmax;
    if (ww->strip_chart.valuedata[i] > ww->strip_chart.max_value)
      ww->strip_chart.max_value = ww->strip_chart.valuedata[i];
    }
  XClearWindow( XtDisplay(w), XtWindow(w));
  ww->strip_chart.interval = repaint_window(ww, 0, (int)w->core.width);
  }

/* Pass back the new value at the new scale */

*ptr = ((double)newvalue * 10.0)/(double)(stripchart_max[num]);
}



/*************************************************
*            Create one stripchart               *
*************************************************/

/* This function creates two widgets, one being the title and the other being
the stripchart. The client_data values for each stripchart are index into the
stripchart_values vector; each new stripchart just gets the next number. There
is a fudge for the very first stripchart, which is the queue length display,
and for the second if it is a partition size display; its update time is
initially set to 1 second so that it gives an immediate display of the queue.
The first time its callback function is obeyed, the update time gets reset. */

void
create_stripchart(Widget parent, uschar *title)
{
Widget chart;

Widget label = XtCreateManagedWidget("label",
  labelWidgetClass, parent, NULL, 0);

xs_SetValues(label, 10,
  "label",          title,
  "width",          stripchart_width + 2,
  "borderWidth",    0,
  "internalHeight", 0,
  "internalWidth",  0,
  "left",           XawChainLeft,
  "right",          XawChainLeft,
  "top",            XawChainTop,
  "bottom",         XawChainTop,
  XtNfromHoriz,     stripchart_prev_label);

chart = XtCreateManagedWidget("stripchart",
  mystripChartWidgetClass, parent, NULL, 0);

xs_SetValues(chart, 11,
  "jumpScroll", 1,
  "update",     (stripchart_count < stripchart_varstart)? 1:stripchart_update,
  "minScale",   10,
  "width",      stripchart_width,
  "height",     stripchart_height,
  "left",       XawChainLeft,
  "right",      XawChainLeft,
  "top",        XawChainTop,
  "bottom",     XawChainTop,
  XtNfromHoriz, stripchart_prev_chart,
  XtNfromVert,  label);

XtAddCallback(chart, "getValue", stripchartAction,
  (XtPointer)(long)stripchart_count);

stripchart_last_total[stripchart_count] = 0;
stripchart_max[stripchart_count] = 10;
stripchart_midmax[stripchart_count] = 0;
stripchart_name[stripchart_count] = title;
stripchart_prev_label = stripchart_label[stripchart_count] = label;
stripchart_prev_chart = chart;
stripchart_total[stripchart_count] = 0;
stripchart_count++;
}

/* End of em_strip.c */