Merge pull request #200 from kenchiang/onlp-snmpd4

Update resources and sensors in separate thread
This commit is contained in:
Jeffrey Townsend
2017-05-06 07:40:09 -07:00
committed by GitHub
4 changed files with 318 additions and 109 deletions

View File

@@ -8,5 +8,9 @@
#include <onlp_snmp/onlp_snmp_config.h>
int onlp_snmp_sensors_init(void);
int onlp_snmp_sensor_update_start(void);
int onlp_snmp_platform_init(void);
int onlp_snmp_platform_update_start(void);
#endif /* __ONLP_SNMP_INT_H__ */

View File

@@ -6,6 +6,7 @@
#include <onlp_snmp/onlp_snmp_config.h>
#include <onlp/onlp.h>
#include "onlp_snmp_log.h"
#include "onlp_snmp_int.h"
static int
datatypes_init__(void)
@@ -37,14 +38,12 @@ void __onlp_snmp_module_init__(void)
static int
onlp_snmp_client__(int enable, void* cookie)
{
/* onlp_snmp_sensors.c */
extern int onlp_snmp_sensors_init(void);
/* onlp_snmp_platform.c */
extern int onlp_snmp_platform_init(void);
onlp_snmp_sensors_init();
onlp_snmp_platform_init();
onlp_snmp_sensor_update_start();
onlp_snmp_platform_update_start();
return 0;
}

View File

@@ -1,7 +1,7 @@
/************************************************************
* <bsn.cl fy=2015 v=onl>
*
* Copyright 2015 Big Switch Networks, Inc.
* Copyright 2015-2017 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the
* "License"); you may not use this file except in compliance
@@ -33,6 +33,9 @@
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <onlp/sys.h>
#include <pthread.h>
#include <unistd.h>
static void
platform_string_register(int index, const char* desc, char* value)
{
@@ -88,6 +91,8 @@ resource_int_register(int index, const char* desc,
}
}
/* updates happen in this pthread */
static pthread_t update_thread_handle;
/* resource objects */
typedef struct {
@@ -95,16 +100,38 @@ typedef struct {
uint32_t idle_percent;
} resources_t;
static resources_t resources;
static uint64_t resource_update_time;
#define NUM_RESOURCE_BUFFERS (2)
static resources_t resources[NUM_RESOURCE_BUFFERS];
static uint64_t last_resource_update_time;
static int curr_resource;
static int
next_resource(void)
{
return (curr_resource+1) % NUM_RESOURCE_BUFFERS;
}
static resources_t *
get_curr_resources(void)
{
return &resources[curr_resource];
}
static resources_t *
get_next_resources(void)
{
return &resources[next_resource()];
}
static void
swap_curr_next_resources(void)
{
curr_resource = next_resource();
}
void resource_update(void)
static void
resource_update(void)
{
uint64_t now = aim_time_monotonic();
if (now - resource_update_time >
if (now - last_resource_update_time >
(ONLP_SNMP_CONFIG_RESOURCE_UPDATE_SECONDS * 1000 * 1000)) {
resource_update_time = now;
AIM_LOG_INFO("update resource objects");
last_resource_update_time = now;
/* invoke mpstat collection script for json output */
FILE *fp = popen("/usr/bin/onl-snmp-mpstat", "r");
@@ -120,9 +147,12 @@ void resource_update(void)
int result;
int rv = cjson_util_lookup_int(root, &result, "all.%%idle");
if (rv == 0) {
resources_t *next = get_next_resources();
/* save it */
resources.idle_percent = result;
resources.utilization_percent = 100*100 - result;
next->idle_percent = result;
next->utilization_percent = 100*100 - result;
/* swap buffers */
swap_curr_next_resources();
}
cJSON_Delete(root);
}
@@ -138,10 +168,10 @@ utilization_handler(netsnmp_mib_handler *handler,
netsnmp_request_info *requests)
{
if (MODE_GET == reqinfo->mode) {
resource_update();
resources_t *curr = get_curr_resources();
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
(u_char *) &resources.utilization_percent,
sizeof(resources.utilization_percent));
(u_char *) &curr->utilization_percent,
sizeof(curr->utilization_percent));
} else {
netsnmp_assert("bad mode in RO handler");
}
@@ -160,10 +190,10 @@ idle_handler(netsnmp_mib_handler *handler,
netsnmp_request_info *requests)
{
if (MODE_GET == reqinfo->mode) {
resource_update();
resources_t *curr = get_curr_resources();
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
(u_char *) &resources.idle_percent,
sizeof(resources.idle_percent));
(u_char *) &curr->idle_percent,
sizeof(curr->idle_percent));
} else {
netsnmp_assert("bad mode in RO handler");
}
@@ -220,3 +250,39 @@ onlp_snmp_platform_init(void)
resource_int_register(2, "CpuAllPercentIdle", idle_handler);
}
#define MIN(a,b) ((a)<(b)? (a): (b))
static unsigned int
us_to_next_update(void)
{
uint64_t deltat = aim_time_monotonic() - last_resource_update_time;
uint64_t period = ONLP_SNMP_CONFIG_RESOURCE_UPDATE_SECONDS * 1000 * 1000;
return MIN(period - deltat, period);
}
static void *
do_update(void *arg)
{
for (;;) {
resource_update();
usleep(us_to_next_update());
}
return NULL;
}
int
onlp_snmp_platform_update_start(void)
{
if (pthread_create(&update_thread_handle, NULL, do_update, NULL) < 0) {
AIM_LOG_ERROR("update thread creation failed");
return -1;
}
return 0;
}
int
onlp_snmp_platform_update_stop(void)
{
pthread_join(update_thread_handle, NULL);
return 0;
}

View File

@@ -1,7 +1,7 @@
/************************************************************
* <bsn.cl fy=2015 v=onl>
*
* Copyright 2015-2016 Big Switch Networks, Inc.
* Copyright 2015-2017 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the
* "License"); you may not use this file except in compliance
@@ -29,7 +29,11 @@
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <OS/os_time.h>
#include <AIM/aim_sem.h>
#include <AIM/aim_time.h>
#include <pthread.h>
#include <unistd.h>
#include <onlp/thermal.h>
#include <onlp/fan.h>
@@ -38,8 +42,24 @@
#include "onlp_snmp_log.h"
typedef struct sensor_info_s {
bool valid; /* for snmp table maintenance */
union {
onlp_thermal_info_t ti;
onlp_fan_info_t fi;
onlp_psu_info_t pi;
} data;
} sensor_info_t;
/* for front-back buffers */
#define NUM_SENSOR_INFO (2)
/**
* Individual Sensor Control structure.
* The valid field in the sensor_info_t structure above
* is used snmp table maintenance:
* - A table row is added when previously invalid sensor is now valid.
* - A table row is deleted when previously valid sensor is now invalid
*/
typedef struct onlp_snmp_sensor_s {
list_links_t links; /* for tracking sensors of the same type */
@@ -48,18 +68,41 @@ typedef struct onlp_snmp_sensor_s {
char desc[ONLP_SNMP_CONFIG_MAX_DESC_LENGTH];
onlp_snmp_sensor_type_t sensor_type;
uint32_t index; /* snmp table column */
union sensor_info {
onlp_thermal_info_t ti;
onlp_fan_info_t fi;
onlp_psu_info_t pi;
} sensor_info;
/* for snmp table maintenance:
* table row is added when previously invalid sensor is now valid,
* table row is deleted when previously valid sensor is now invalid */
bool previously_valid;
bool now_valid;
sensor_info_t sensor_info[NUM_SENSOR_INFO];
} onlp_snmp_sensor_t;
static int curr_info;
static int
next_info(void)
{
return (curr_info+1) % NUM_SENSOR_INFO;
}
static sensor_info_t *
get_curr_info(onlp_snmp_sensor_t *ss)
{
return &ss->sensor_info[curr_info];
}
static sensor_info_t *
get_next_info(onlp_snmp_sensor_t *ss)
{
return &ss->sensor_info[next_info()];
}
static void
swap_curr_next_info(void)
{
curr_info = next_info();
}
/* timestamp used to trigger sensor update */
static uint64_t last_sensor_update_time;
/* true if table restructuring is to happen;
* set after all tables updated;
* cleared after all tables restructured */
static bool restructure_trigger;
/* updates happen in this pthread */
static pthread_t update_thread_handle;
/**
* NET SNMP handler
@@ -73,12 +116,6 @@ typedef void (*onlp_snmp_handler_fn)(netsnmp_request_info *req,
typedef int (*update_handler_fn)(onlp_snmp_sensor_t *ss);
/*
* Sensor Value Update period
*/
static uint32_t update_period__ = ONLP_SNMP_CONFIG_UPDATE_PERIOD;
/*
* Sensor control block, one for each sensor type
*/
@@ -238,7 +275,7 @@ register_table__(char table_name[], oid table_oid[], size_t table_oid_len,
static int
temp_update_handler__(onlp_snmp_sensor_t *ss)
{
onlp_thermal_info_t *ti = &ss->sensor_info.ti;
onlp_thermal_info_t *ti = &get_next_info(ss)->data.ti;
onlp_oid_t oid = (onlp_oid_t) ss->sensor_id;
return onlp_thermal_info_get(oid, ti);
@@ -276,9 +313,10 @@ temp_status_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int value;
onlp_thermal_info_t *ti = &ss->sensor_info.ti;
sensor_info_t *si = get_curr_info(ss);
onlp_thermal_info_t *ti = &si->data.ti;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -301,9 +339,10 @@ temp_value_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int value;
onlp_thermal_info_t *ti = &ss->sensor_info.ti;
sensor_info_t *si = get_curr_info(ss);
onlp_thermal_info_t *ti = &si->data.ti;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -340,7 +379,7 @@ temp_table_handler__(netsnmp_mib_handler *handler,
static int
fan_update_handler__(onlp_snmp_sensor_t *ss)
{
onlp_fan_info_t *fi = &ss->sensor_info.fi;
onlp_fan_info_t *fi = &get_next_info(ss)->data.fi;
onlp_oid_t oid = (onlp_oid_t) ss->sensor_id;
return onlp_fan_info_get(oid, fi);
@@ -378,9 +417,10 @@ fan_status_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int value;
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -403,9 +443,10 @@ fan_flow_type_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int name_index;
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -433,9 +474,10 @@ fan_rpm_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int value;
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -453,9 +495,10 @@ fan_pct_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss)
{
int value;
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -472,9 +515,10 @@ fan_model_handler__(netsnmp_request_info *req,
uint32_t index,
onlp_snmp_sensor_t *ss)
{
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -491,9 +535,10 @@ fan_serial_handler__(netsnmp_request_info *req,
uint32_t index,
onlp_snmp_sensor_t *ss)
{
onlp_fan_info_t *fi = &ss->sensor_info.fi;
sensor_info_t *si = get_curr_info(ss);
onlp_fan_info_t *fi = &si->data.fi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -534,7 +579,7 @@ fan_table_handler__(netsnmp_mib_handler *handler,
static int
psu_update_handler__(onlp_snmp_sensor_t *ss)
{
onlp_psu_info_t *pi = &ss->sensor_info.pi;
onlp_psu_info_t *pi = &get_next_info(ss)->data.pi;
onlp_oid_t oid = (onlp_oid_t) ss->sensor_id;
return onlp_psu_info_get(oid, pi);
@@ -571,9 +616,10 @@ psu_status_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -604,9 +650,10 @@ psu_current_type_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int name_index;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -633,10 +680,10 @@ psu_model_handler__(netsnmp_request_info *req,
uint32_t index,
onlp_snmp_sensor_t *ss)
{
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -653,10 +700,10 @@ psu_serial_handler__(netsnmp_request_info *req,
uint32_t index,
onlp_snmp_sensor_t *ss)
{
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -674,9 +721,10 @@ psu_vin_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -694,9 +742,10 @@ psu_vout_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -714,9 +763,10 @@ psu_iin_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -734,9 +784,10 @@ psu_iout_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -754,9 +805,10 @@ psu_pin_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -774,9 +826,10 @@ psu_pout_handler__(netsnmp_request_info *req,
onlp_snmp_sensor_t *ss )
{
int value;
onlp_psu_info_t *pi = &ss->sensor_info.pi;
sensor_info_t *si = get_curr_info(ss);
onlp_psu_info_t *pi = &si->data.pi;
if (!ss->now_valid) {
if (!si->valid) {
return;
}
@@ -829,6 +882,7 @@ static update_handler_fn all_update_handler_fns__[] = {
/*
* Add a sensor to the appropriate type-specific control structure.
* Updates next sensor info, not current sensor info.
*/
static void
add_sensor__(int sensor_type, onlp_snmp_sensor_t *new_sensor)
@@ -848,7 +902,7 @@ add_sensor__(int sensor_type, onlp_snmp_sensor_t *new_sensor)
if (new_sensor->sensor_id == ss->sensor_id) {
/* no need to add sensor */
AIM_LOG_TRACE("skipping existing sensor %08x", ss->sensor_id);
ss->now_valid = true;
get_next_info(ss)->valid = true;
return;
}
}
@@ -857,7 +911,7 @@ add_sensor__(int sensor_type, onlp_snmp_sensor_t *new_sensor)
AIM_TRUE_OR_DIE(ss);
AIM_MEMCPY(ss, new_sensor, sizeof(*new_sensor));
ss->sensor_type = sensor_type;
ss->now_valid = true;
get_next_info(ss)->valid = true;
/* finally add sensor */
list_push(&ctrl->sensors, &ss->links);
@@ -918,26 +972,48 @@ collect_sensors__(onlp_oid_t oid, void* cookie)
}
static int
update_all_tables__(void)
/*
* sensor table is updated in two parts:
* 1. sensor update, performed in separate thread by calling update_tables__.
* once update is complete, front-back buffers will be switched
* and flag set to indicate table restructuring can occur
* 2. sensor table restructuring, performed in snmp callback
* by calling restructure_tables__.
*/
static void
update_tables__(void)
{
int i;
onlp_snmp_sensor_ctrl_t *ctrl;
list_links_t *curr;
list_links_t *next;
onlp_snmp_sensor_t *ss;
/* for each table: save old state */
uint64_t now = aim_time_monotonic();
if (now - last_sensor_update_time <
(ONLP_SNMP_CONFIG_UPDATE_PERIOD * 1000 * 1000)) {
return;
}
if (restructure_trigger) {
AIM_LOG_INFO("restructure has not happened, skip sensor update");
return;
}
last_sensor_update_time = now;
AIM_LOG_TRACE("update sensor objects");
/* for each table: mark next_info invalid */
for (i = ONLP_SNMP_SENSOR_TYPE_TEMP; i <= ONLP_SNMP_SENSOR_TYPE_MAX; i++) {
ctrl = get_sensor_ctrl__(i);
LIST_FOREACH(&ctrl->sensors, curr) {
ss = container_of(curr, links, onlp_snmp_sensor_t);
ss->previously_valid = ss->now_valid;
ss->now_valid = false;
get_next_info(ss)->valid = false;
}
}
/* discover new sensors for all tables */
/* discover new sensors for all tables,
* writing validity into next_info for all sensors */
onlp_oid_iterate(ONLP_OID_SYS, 0, collect_sensors__, NULL);
/* for each table: update all sensor info */
@@ -945,32 +1021,65 @@ update_all_tables__(void)
ctrl = get_sensor_ctrl__(i);
LIST_FOREACH(&ctrl->sensors, curr) {
ss = container_of(curr, links, onlp_snmp_sensor_t);
if (ss->now_valid) {
AIM_LOG_TRACE("update sensor %s%s", ss->name, ss->desc);
if (get_next_info(ss)->valid) {
AIM_LOG_INFO("update sensor %s%s", ss->name, ss->desc);
/* invoke update handler */
if ((*all_update_handler_fns__[i])(ss) != ONLP_STATUS_OK) {
AIM_LOG_ERROR("failed to update %s%s", ss->name, ss->desc);
ss->now_valid = false;
get_next_info(ss)->valid = false;
}
}
}
}
/* swap front and back buffers */
swap_curr_next_info();
/* trigger table restructuring */
AIM_LOG_TRACE("trigger restructure");
restructure_trigger = true;
}
/*
* adds or removes rows from sensor table.
* registered with snmp_alarm_register.
* table restructuring then happens within alarm handler,
* thus avoiding crashes when table is changed while handling snmp requests.
*/
static void
restructure_tables__(unsigned int reg, void *clientarg)
{
int i;
onlp_snmp_sensor_ctrl_t *ctrl;
list_links_t *curr;
list_links_t *next;
onlp_snmp_sensor_t *ss;
bool previously_valid;
bool now_valid;
if (!restructure_trigger) {
return;
}
AIM_LOG_INFO("restructuring tables");
/* for each table: add or delete rows as necessary */
for (i = ONLP_SNMP_SENSOR_TYPE_TEMP; i <= ONLP_SNMP_SENSOR_TYPE_MAX; i++) {
ctrl = get_sensor_ctrl__(i);
LIST_FOREACH_SAFE(&ctrl->sensors, curr, next) {
ss = container_of(curr, links, onlp_snmp_sensor_t);
if (!ss->previously_valid && ss->now_valid) {
previously_valid = get_next_info(ss)->valid;
now_valid = get_curr_info(ss)->valid;
if (!previously_valid && now_valid) {
snmp_log(LOG_INFO, "Adding %s%s, id=%08x",
ss->name, ss->desc, ss->sensor_id);
AIM_LOG_VERBOSE("add row %d to %s for %s%s",
AIM_LOG_INFO("add row %d to %s for %s%s",
ss->index, ctrl->name, ss->name, ss->desc);
add_table_row__(sensor_table__[i], ss);
} else if (ss->previously_valid && !ss->now_valid) {
} else if (previously_valid && !now_valid) {
snmp_log(LOG_INFO, "Deleting %s%s, id=%08x",
ss->name, ss->desc, ss->sensor_id);
AIM_LOG_VERBOSE("delete row %d from %s for %s%s",
AIM_LOG_INFO("delete row %d from %s for %s%s",
ss->index, ctrl->name, ss->name, ss->desc);
delete_table_row__(sensor_table__[i], ss->index);
list_remove(curr);
@@ -979,7 +1088,9 @@ update_all_tables__(void)
}
}
return 0;
AIM_LOG_INFO("restructuring complete");
restructure_trigger = false;
}
@@ -1040,23 +1151,15 @@ init_all_tables__(void)
}
/* helper function to be registered with snmp_alarm_register;
* table updates happen within alarm handler, thus avoiding crashes
* when table is changed while handling snmp requests */
static void
periodic_update__(unsigned int reg, void *clientarg)
{
update_all_tables__();
}
/* populates initial stats and sets up periodic timer */
static void
setup_alarm__(void)
{
/* initial stats population */
update_all_tables__();
/* registration of periodic timer */
snmp_alarm_register(update_period__, SA_REPEAT, periodic_update__, NULL);
/* initial stats population: update and restructure */
update_tables__();
restructure_tables__(0, NULL);
/* registration of periodic timer for table restructuring */
snmp_alarm_register(1, SA_REPEAT, restructure_tables__, NULL);
}
@@ -1067,3 +1170,40 @@ onlp_snmp_sensors_init(void)
setup_alarm__();
return 0;
}
#define MIN(a,b) ((a)<(b)? (a): (b))
static unsigned int
us_to_next_update(void)
{
uint64_t deltat = aim_time_monotonic() - last_sensor_update_time;
uint64_t period = ONLP_SNMP_CONFIG_UPDATE_PERIOD * 1000 * 1000;
return MIN(period - deltat, period);
}
static void *
do_update(void *arg)
{
for (;;) {
update_tables__();
usleep(us_to_next_update());
}
return NULL;
}
int
onlp_snmp_sensor_update_start(void)
{
if (pthread_create(&update_thread_handle, NULL, do_update, NULL) < 0) {
AIM_LOG_ERROR("update thread creation failed");
return -1;
}
return 0;
}
int
onlp_snmp_sensor_update_stop(void)
{
pthread_join(update_thread_handle, NULL);
return 0;
}