summaryrefslogtreecommitdiffstats
path: root/exim_monitor/em_strip.c
diff options
context:
space:
mode:
Diffstat (limited to 'exim_monitor/em_strip.c')
-rw-r--r--exim_monitor/em_strip.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/exim_monitor/em_strip.c b/exim_monitor/em_strip.c
new file mode 100644
index 0000000..2a5f0b8
--- /dev/null
+++ b/exim_monitor/em_strip.c
@@ -0,0 +1,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, "%");
+ 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 */