summaryrefslogtreecommitdiff
path: root/sys/dev/sysmon
diff options
context:
space:
mode:
authorxtraeme <xtraeme@NetBSD.org>2008-04-01 12:25:30 +0000
committerxtraeme <xtraeme@NetBSD.org>2008-04-01 12:25:30 +0000
commit5ee4eba88daa5874d8a4b2663c986fff47abe941 (patch)
tree3c418f77527c6d347b5aae300b820e69fcd0d2c3 /sys/dev/sysmon
parente9c68c5df07731f273526cca51b211c80704e6d1 (diff)
Introduce per-device locking/synchronization and maintain only a
global mutex for the linked list of devices and the global proplib dictionary. This has improved locking contention a lot when multiple devices with multiple monitoring events are running: New: 0.30 35 0.33 sme_global_mtx sysmonioctl_envsys+28b 0.10 10 0.11 00000000cd97feac sysmon_envsys_acquire+4c 0.08 6 0.09 00000000cd97feac sme_update_dictionary+24f 0.01 4 0.01 00000000cd97feac sme_events_worker+2f 0.01 10 0.01 00000000cd97fe2c sysmon_envsys_acquire+4c 0.00 1 0.00 00000000cd97fe2c sysmon_envsys_release+3b 28.38 94 9.16 sme_global_mtx sysmonioctl_envsys+28b 4.54 74 1.47 00000000cd97fe2c sysmon_envsys_acquire+4c 0.06 3 0.02 00000000cd97fe2c sysmon_envsys_release+3b 0.03 1 0.01 00000000cd97fe2c sme_events_worker+2f 1.40 19 0.45 00000000cd97bee4 sysmon_envsys_acquire+4c Old: 4.25 313 4.74 sme_mtx <all> 3.12 185 3.49 sme_mtx sme_events_worker+21 1.12 128 1.25 sme_mtx sysmonioctl_envsys+29b 34.75 1423 59.52 sme_mtx <all> 22.08 477 37.82 sme_mtx sysmonioctl_envsys+29b 12.67 946 21.70 sme_mtx sme_events_worker+21
Diffstat (limited to 'sys/dev/sysmon')
-rw-r--r--sys/dev/sysmon/sysmon_envsys.c408
-rw-r--r--sys/dev/sysmon/sysmon_envsys_events.c238
-rw-r--r--sys/dev/sysmon/sysmon_envsysvar.h17
-rw-r--r--sys/dev/sysmon/sysmonvar.h15
4 files changed, 349 insertions, 329 deletions
diff --git a/sys/dev/sysmon/sysmon_envsys.c b/sys/dev/sysmon/sysmon_envsys.c
index 583ce8f180c..2ee2cfa604a 100644
--- a/sys/dev/sysmon/sysmon_envsys.c
+++ b/sys/dev/sysmon/sysmon_envsys.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sysmon_envsys.c,v 1.81 2008/03/23 16:09:41 xtraeme Exp $ */
+/* $NetBSD: sysmon_envsys.c,v 1.82 2008/04/01 12:25:30 xtraeme Exp $ */
/*-
* Copyright (c) 2007, 2008 Juan Romero Pardines.
@@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.81 2008/03/23 16:09:41 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.82 2008/04/01 12:25:30 xtraeme Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -82,24 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.81 2008/03/23 16:09:41 xtraeme E
#include <dev/sysmon/sysmon_envsysvar.h>
#include <dev/sysmon/sysmon_taskq.h>
-/*
- * Notes about locking:
- *
- * The 'sme_mtx' lock is used to protect access to the sysmon_envsys
- * objects (devices, sensors, events) and the global counter
- * 'sysmon_envsys_next_sensor_index'. The 'sme_cv' condition variable
- * is used to wait for completion paths on these objects.
- *
- * The 'sme_events_mtx' lock is used to protect initialization and
- * finalization of the per device events framework (the callout(9) and
- * workqueue(9) that is used to check for conditions and sending events
- * to the powerd(8) daemon (if running)).
- *
- * The callouts are protected by the 'sme_callout_mtx'.
- */
-
-kmutex_t sme_mtx, sme_events_mtx, sme_callout_mtx;
-kcondvar_t sme_cv;
+kmutex_t sme_global_mtx;
/*
* Types of properties that can be set via userland.
@@ -113,7 +96,7 @@ enum {
};
static prop_dictionary_t sme_propd;
-static uint32_t sysmon_envsys_next_sensor_index = 0;
+static uint32_t sysmon_envsys_next_sensor_index;
static struct sysmon_envsys *sysmon_envsys_find_40(u_int);
static void sysmon_envsys_destroy_plist(prop_array_t);
@@ -125,16 +108,13 @@ static void sme_initial_refresh(void *);
/*
* sysmon_envsys_init:
*
- * + Initialize global mutexes, dictionary and the linked lists.
+ * + Initialize global mutex, dictionary and the linked list.
*/
void
sysmon_envsys_init(void)
{
LIST_INIT(&sysmon_envsys_list);
- mutex_init(&sme_mtx, MUTEX_DEFAULT, IPL_NONE);
- mutex_init(&sme_events_mtx, MUTEX_DEFAULT, IPL_NONE);
- mutex_init(&sme_callout_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
- cv_init(&sme_cv, "smeworker");
+ mutex_init(&sme_global_mtx, MUTEX_DEFAULT, IPL_NONE);
sme_propd = prop_dictionary_create();
}
@@ -184,20 +164,20 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
* Update dictionaries on all sysmon envsys devices
* registered.
*/
- mutex_enter(&sme_mtx);
+ mutex_enter(&sme_global_mtx);
LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
- sysmon_envsys_acquire(sme);
+ sysmon_envsys_acquire(sme, false);
error = sme_update_dictionary(sme);
if (error) {
DPRINTF(("%s: sme_update_dictionary, "
"error=%d\n", __func__, error));
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
+ mutex_exit(&sme_global_mtx);
return error;
}
- sysmon_envsys_release(sme);
+ sysmon_envsys_release(sme, false);
}
- mutex_exit(&sme_mtx);
+ mutex_exit(&sme_global_mtx);
/*
* Copy global dictionary to userland.
*/
@@ -254,10 +234,8 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
/*
* find the correct sme device.
*/
- mutex_enter(&sme_mtx);
sme = sysmon_envsys_find(devname);
if (!sme) {
- mutex_exit(&sme_mtx);
DPRINTF(("%s: NULL sme\n", __func__));
prop_object_iterator_release(iter);
prop_object_release(udict);
@@ -272,8 +250,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
if (prop_object_type(array_k) != PROP_TYPE_ARRAY) {
DPRINTF(("%s: array device failed\n",
__func__));
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
prop_object_iterator_release(iter);
prop_object_release(udict);
return EINVAL;
@@ -281,8 +258,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
iter2 = prop_array_iterator(array_u);
if (!iter2) {
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
prop_object_iterator_release(iter);
prop_object_release(udict);
return ENOMEM;
@@ -300,8 +276,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
obj2,
array_k);
if (error) {
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
prop_object_iterator_release(iter2);
prop_object_iterator_release(iter);
prop_object_release(udict);
@@ -309,8 +284,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
}
}
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
prop_object_iterator_release(iter2);
}
@@ -362,12 +336,9 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
tred->validflags = 0;
- mutex_enter(&sme_mtx);
sme = sysmon_envsys_find_40(tred->sensor);
- if (!sme) {
- mutex_exit(&sme_mtx);
+ if (!sme)
break;
- }
oidx = tred->sensor;
tred->sensor = SME_SENSOR_IDX(sme, tred->sensor);
@@ -384,15 +355,17 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
}
if (!found) {
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
error = ENODEV;
break;
}
if (tred->sensor < sme->sme_nsensors) {
- if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0)
+ if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0) {
+ mutex_enter(&sme->sme_mtx);
(*sme->sme_refresh)(sme, edata);
+ mutex_exit(&sme->sme_mtx);
+ }
/*
* copy required values to the old interface.
@@ -431,8 +404,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
tred->units, tred->sensor));
}
tred->sensor = oidx;
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
break;
}
@@ -444,12 +416,9 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
binfo->validflags = 0;
- mutex_enter(&sme_mtx);
sme = sysmon_envsys_find_40(binfo->sensor);
- if (!sme) {
- mutex_exit(&sme_mtx);
+ if (!sme)
break;
- }
oidx = binfo->sensor;
binfo->sensor = SME_SENSOR_IDX(sme, binfo->sensor);
@@ -462,8 +431,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
}
if (!found) {
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
error = ENODEV;
break;
}
@@ -494,8 +462,7 @@ sysmonioctl_envsys(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
__func__, binfo->desc, binfo->sensor));
binfo->sensor = oidx;
- sysmon_envsys_release(sme);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, false);
break;
}
@@ -522,6 +489,8 @@ sysmon_envsys_create(void)
TAILQ_INIT(&sme->sme_sensors_list);
LIST_INIT(&sme->sme_events_list);
callout_init(&sme->sme_callout, CALLOUT_MPSAFE);
+ mutex_init(&sme->sme_mtx, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&sme->sme_condvar, "sme_wait");
return sme;
}
@@ -544,6 +513,8 @@ sysmon_envsys_destroy(struct sysmon_envsys *sme)
TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
}
callout_destroy(&sme->sme_callout);
+ mutex_destroy(&sme->sme_mtx);
+ cv_destroy(&sme->sme_condvar);
kmem_free(sme, sizeof(*sme));
}
@@ -579,10 +550,12 @@ sysmon_envsys_sensor_attach(struct sysmon_envsys *sme, envsys_data_t *edata)
if (strlen(edata->desc) == 0)
return EINVAL;
- mutex_enter(&sme_mtx);
+ mutex_enter(&sme->sme_mtx);
+ sysmon_envsys_acquire(sme, true);
TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
if (strcmp(oedata->desc, edata->desc) == 0) {
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
return EEXIST;
}
}
@@ -596,7 +569,8 @@ sysmon_envsys_sensor_attach(struct sysmon_envsys *sme, envsys_data_t *edata)
*/
edata->sensor = sme->sme_nsensors;
sme->sme_nsensors++;
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
return 0;
}
@@ -618,7 +592,8 @@ sysmon_envsys_sensor_detach(struct sysmon_envsys *sme, envsys_data_t *edata)
/*
* Check the sensor is already on the list.
*/
- mutex_enter(&sme_mtx);
+ mutex_enter(&sme->sme_mtx);
+ sysmon_envsys_acquire(sme, true);
TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
if (oedata->sensor == edata->sensor) {
found = true;
@@ -627,7 +602,8 @@ sysmon_envsys_sensor_detach(struct sysmon_envsys *sme, envsys_data_t *edata)
}
if (!found) {
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
return EINVAL;
}
@@ -636,7 +612,8 @@ sysmon_envsys_sensor_detach(struct sysmon_envsys *sme, envsys_data_t *edata)
*/
TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
sme->sme_nsensors--;
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
return 0;
}
@@ -656,10 +633,10 @@ sysmon_envsys_register(struct sysmon_envsys *sme)
sme_event_drv_t *evdrv;
};
SLIST_HEAD(, sme_evdrv) sme_evdrv_list;
- struct sme_evdrv *sme_evdrv = NULL;
+ struct sme_evdrv *evdv = NULL;
struct sysmon_envsys *lsme;
+ prop_array_t array = NULL;
prop_dictionary_t dict, dict2;
- prop_array_t array;
envsys_data_t *edata = NULL;
int error = 0;
@@ -667,6 +644,19 @@ sysmon_envsys_register(struct sysmon_envsys *sme)
KASSERT(sme->sme_name != NULL);
/*
+ * Check if requested sysmon_envsys device is valid
+ * and does not exist already in the list.
+ */
+ mutex_enter(&sme_global_mtx);
+ LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
+ if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
+ mutex_exit(&sme_global_mtx);
+ return EEXIST;
+ }
+ }
+ mutex_exit(&sme_global_mtx);
+
+ /*
* sanity check: if SME_DISABLE_REFRESH is not set,
* the sme_refresh function callback must be non NULL.
*/
@@ -684,18 +674,15 @@ sysmon_envsys_register(struct sysmon_envsys *sme)
}
/*
- * create the device array.
+ * Initialize the singly linked list for driver events.
*/
+ SLIST_INIT(&sme_evdrv_list);
+
array = prop_array_create();
if (!array)
return ENOMEM;
/*
- * Initialize the singly linked list for driver events.
- */
- SLIST_INIT(&sme_evdrv_list);
-
- /*
* Iterate over all sensors and create a dictionary per sensor.
* We must respect the order in which the sensors were added.
*/
@@ -709,24 +696,11 @@ sysmon_envsys_register(struct sysmon_envsys *sme)
/*
* Create all objects in sensor's dictionary.
*/
- sme_evdrv = kmem_zalloc(sizeof(*sme_evdrv), KM_SLEEP);
- sme_evdrv->evdrv = sme_add_sensor_dictionary(sme,
- array, dict, edata);
- if (sme_evdrv->evdrv)
- SLIST_INSERT_HEAD(&sme_evdrv_list,
- sme_evdrv, evdrv_head);
- }
-
- /*
- * Check if requested sysmon_envsys device is valid
- * and does not exist already in the list.
- */
- mutex_enter(&sme_mtx);
- LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
- if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
- error = EEXIST;
- goto out;
- }
+ evdv = kmem_zalloc(sizeof(*evdv), KM_SLEEP);
+ evdv->evdrv = sme_add_sensor_dictionary(sme, array,
+ dict, edata);
+ if (evdv->evdrv)
+ SLIST_INSERT_HEAD(&sme_evdrv_list, evdv, evdrv_head);
}
/*
@@ -763,30 +737,32 @@ sysmon_envsys_register(struct sysmon_envsys *sme)
* <array>
* ...
*/
+ mutex_enter(&sme_global_mtx);
if (!prop_dictionary_set(sme_propd, sme->sme_name, array)) {
error = EINVAL;
DPRINTF(("%s: prop_dictionary_set for '%s'\n", __func__,
sme->sme_name));
goto out;
}
+
/*
* Add the device into the list.
*/
LIST_INSERT_HEAD(&sysmon_envsys_list, sme, sme_list);
sme->sme_fsensor = sysmon_envsys_next_sensor_index;
sysmon_envsys_next_sensor_index += sme->sme_nsensors;
-out:
- mutex_exit(&sme_mtx);
+ mutex_exit(&sme_global_mtx);
+out:
/*
* No errors? register the events that were set in the driver
* and make an initial data refresh if was requested.
*/
if (error == 0) {
sysmon_task_queue_init();
- SLIST_FOREACH(sme_evdrv, &sme_evdrv_list, evdrv_head) {
+ SLIST_FOREACH(evdv, &sme_evdrv_list, evdrv_head) {
sysmon_task_queue_sched(0,
- sme_event_drvadd, sme_evdrv->evdrv);
+ sme_event_drvadd, evdv->evdrv);
}
DPRINTF(("%s: driver '%s' registered (nsens=%d)\n",
__func__, sme->sme_name, sme->sme_nsensors));
@@ -797,9 +773,9 @@ out:
out2:
while (!SLIST_EMPTY(&sme_evdrv_list)) {
- sme_evdrv = SLIST_FIRST(&sme_evdrv_list);
+ evdv = SLIST_FIRST(&sme_evdrv_list);
SLIST_REMOVE_HEAD(&sme_evdrv_list, evdrv_head);
- kmem_free(sme_evdrv, sizeof(*sme_evdrv));
+ kmem_free(evdv, sizeof(*evdv));
}
if (!error)
return 0;
@@ -810,15 +786,11 @@ out2:
*/
DPRINTF(("%s: failed to register '%s' (%d)\n", __func__,
sme->sme_name, error));
- if (error != EEXIST) {
- mutex_enter(&sme_mtx);
- sme_event_unregister_all(sme);
- while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
- edata = TAILQ_FIRST(&sme->sme_sensors_list);
- TAILQ_REMOVE(&sme->sme_sensors_list, edata,
- sensors_head);
- }
- mutex_exit(&sme_mtx);
+
+ sme_event_unregister_all(sme);
+ while (!TAILQ_EMPTY(&sme->sme_sensors_list)) {
+ edata = TAILQ_FIRST(&sme->sme_sensors_list);
+ TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
}
sysmon_envsys_destroy_plist(array);
return error;
@@ -838,6 +810,7 @@ sysmon_envsys_destroy_plist(prop_array_t array)
prop_object_t obj;
KASSERT(array != NULL);
+ KASSERT(prop_object_type(array) == PROP_TYPE_ARRAY);
DPRINTFOBJ(("%s: objects in array=%d\n", __func__,
prop_array_count(array)));
@@ -882,32 +855,33 @@ sysmon_envsys_unregister(struct sysmon_envsys *sme)
KASSERT(sme != NULL);
- mutex_enter(&sme_mtx);
/*
- * Wait for device to be available.
- */
- while (sme->sme_flags & SME_FLAG_BUSY)
- cv_wait(&sme_cv, &sme_mtx);
- /*
- * Stop the callout.
+ * Unregister all events associated with device and stop the
+ * callout; after this it's safe to unregister it.
*/
+ sme_event_unregister_all(sme);
+ mutex_enter(&sme->sme_mtx);
+ sysmon_envsys_acquire(sme, true);
callout_stop(&sme->sme_callout);
/*
- * Decrement global sensors counter (only useful for compatibility).
+ * Decrement global sensors counter (only used for compatibility
+ * with previous API) and remove the device from the list.
*/
+ mutex_enter(&sme_global_mtx);
sysmon_envsys_next_sensor_index -= sme->sme_nsensors;
- /*
- * Unregister all events associated with this device.
- */
- sme_event_unregister_all(sme);
LIST_REMOVE(sme, sme_list);
- mutex_exit(&sme_mtx);
+ mutex_exit(&sme_global_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
+
/*
* Remove the device (and all its objects) from the global dictionary.
*/
array = prop_dictionary_get(sme_propd, sme->sme_name);
if (array && prop_object_type(array) == PROP_TYPE_ARRAY) {
+ mutex_enter(&sme_global_mtx);
prop_dictionary_remove(sme_propd, sme->sme_name);
+ mutex_exit(&sme_global_mtx);
sysmon_envsys_destroy_plist(array);
}
/*
@@ -919,80 +893,91 @@ sysmon_envsys_unregister(struct sysmon_envsys *sme)
/*
* sysmon_envsys_find:
*
- * + Find a sysmon envsys device and mark it as busy if found.
+ * + Find a sysmon envsys device and mark it as busy
+ * once it's available.
*/
struct sysmon_envsys *
sysmon_envsys_find(const char *name)
{
struct sysmon_envsys *sme;
- KASSERT(mutex_owned(&sme_mtx));
-
-again:
+ mutex_enter(&sme_global_mtx);
LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
if (strcmp(sme->sme_name, name) == 0) {
- if (sme->sme_flags & SME_FLAG_BUSY) {
- cv_wait(&sme_cv, &sme_mtx);
- goto again;
- }
- sme->sme_flags |= SME_FLAG_BUSY;
+ sysmon_envsys_acquire(sme, false);
break;
}
}
+ mutex_exit(&sme_global_mtx);
+
return sme;
}
/*
- * sysmon_envsys_acquire:
- *
- * + Acquire priviledge to a sysmon envsys device (locked).
+ * Compatibility function with the old API.
*/
-void
-sysmon_envsys_acquire(struct sysmon_envsys *sme)
+struct sysmon_envsys *
+sysmon_envsys_find_40(u_int idx)
{
- KASSERT(mutex_owned(&sme_mtx));
+ struct sysmon_envsys *sme;
- while (sme->sme_flags & SME_FLAG_BUSY)
- cv_wait(&sme_cv, &sme_mtx);
+ mutex_enter(&sme_global_mtx);
+ LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
+ if (idx >= sme->sme_fsensor &&
+ idx < (sme->sme_fsensor + sme->sme_nsensors)) {
+ sysmon_envsys_acquire(sme, false);
+ break;
+ }
+ }
+ mutex_exit(&sme_global_mtx);
- sme->sme_flags |= SME_FLAG_BUSY;
+ return sme;
}
/*
- * sysmon_envsys_release:
+ * sysmon_envsys_acquire:
*
- * + Release a sysmon envsys device (locked).
+ * + Wait until a sysmon envsys device is available and mark
+ * it as busy.
*/
void
-sysmon_envsys_release(struct sysmon_envsys *sme)
+sysmon_envsys_acquire(struct sysmon_envsys *sme, bool locked)
{
- KASSERT(mutex_owned(&sme_mtx));
+ KASSERT(sme != NULL);
- sme->sme_flags &= ~SME_FLAG_BUSY;
- cv_broadcast(&sme_cv);
+ if (locked) {
+ while (sme->sme_flags & SME_FLAG_BUSY)
+ cv_wait(&sme->sme_condvar, &sme->sme_mtx);
+ sme->sme_flags |= SME_FLAG_BUSY;
+ } else {
+ mutex_enter(&sme->sme_mtx);
+ while (sme->sme_flags & SME_FLAG_BUSY)
+ cv_wait(&sme->sme_condvar, &sme->sme_mtx);
+ sme->sme_flags |= SME_FLAG_BUSY;
+ mutex_exit(&sme->sme_mtx);
+ }
}
-/* compatibility function */
-struct sysmon_envsys *
-sysmon_envsys_find_40(u_int idx)
+/*
+ * sysmon_envsys_release:
+ *
+ * + Unmark a sysmon envsys device as busy, and notify
+ * waiters.
+ */
+void
+sysmon_envsys_release(struct sysmon_envsys *sme, bool locked)
{
- struct sysmon_envsys *sme;
-
- KASSERT(mutex_owned(&sme_mtx));
+ KASSERT(sme != NULL);
-again:
- LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
- if (idx >= sme->sme_fsensor &&
- idx < (sme->sme_fsensor + sme->sme_nsensors)) {
- if (sme->sme_flags & SME_FLAG_BUSY) {
- cv_wait(&sme_cv, &sme_mtx);
- goto again;
- }
- sme->sme_flags |= SME_FLAG_BUSY;
- break;
- }
+ if (locked) {
+ sme->sme_flags &= ~SME_FLAG_BUSY;
+ cv_broadcast(&sme->sme_condvar);
+ } else {
+ mutex_enter(&sme->sme_mtx);
+ sme->sme_flags &= ~SME_FLAG_BUSY;
+ cv_broadcast(&sme->sme_condvar);
+ mutex_exit(&sme->sme_mtx);
}
- return sme;
}
/*
@@ -1008,10 +993,12 @@ sme_initial_refresh(void *arg)
struct sysmon_envsys *sme = arg;
envsys_data_t *edata;
- mutex_enter(&sme_mtx);
+ mutex_enter(&sme->sme_mtx);
+ sysmon_envsys_acquire(sme, true);
TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head)
(*sme->sme_refresh)(sme, edata);
- mutex_exit(&sme_mtx);
+ sysmon_envsys_release(sme, true);
+ mutex_exit(&sme->sme_mtx);
}
/*
@@ -1059,9 +1046,9 @@ sme_remove_userprops(void)
char tmp[ENVSYS_DESCLEN];
int ptype;
- mutex_enter(&sme_mtx);
+ mutex_enter(&sme_global_mtx);
LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
- sysmon_envsys_acquire(sme);
+ sysmon_envsys_acquire(sme, false);
array = prop_dictionary_get(sme_propd, sme->sme_name);
TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
@@ -1108,9 +1095,9 @@ sme_remove_userprops(void)
* Restore default timeout value.
*/
sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
- sysmon_envsys_release(sme);
+ sysmon_envsys_release(sme, false);
}
- mutex_exit(&sme_mtx);
+ mutex_exit(&sme_global_mtx);
}
/*
@@ -1432,8 +1419,6 @@ sme_update_dictionary(struct sysmon_envsys *sme)
prop_object_t array, dict, obj, obj2;
int j, error = 0;
- KASSERT(mutex_owned(&sme_mtx));
-
/*
* Retrieve the array of dictionaries in device.
*/
@@ -1473,13 +1458,21 @@ sme_update_dictionary(struct sysmon_envsys *sme)
DPRINTF(("%s: updating '%s' with nsensors=%d\n", __func__,
sme->sme_name, sme->sme_nsensors));
+ /*
+ * Don't bother with locking when traversing the queue,
+ * the device is already marked as busy; if a sensor
+ * is going to be removed or added it will have to wait.
+ */
TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
/*
* refresh sensor data via sme_refresh only if the
* flag is not set.
*/
- if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0)
+ if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0) {
+ mutex_enter(&sme->sme_mtx);
(*sme->sme_refresh)(sme, edata);
+ mutex_exit(&sme->sme_mtx);
+ }
/*
* retrieve sensor's dictionary.
@@ -1656,8 +1649,6 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
const char *blah;
bool targetfound = false;
- KASSERT(mutex_owned(&sme_mtx));
-
/*
* The user wanted to change the refresh timeout value for this
* device.
@@ -1676,10 +1667,13 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
prop_number_unsigned_integer_value(obj1);
if (refresh_timo < 1)
error = EINVAL;
- else
+ else {
+ mutex_enter(&sme->sme_mtx);
sme->sme_events_timeout = refresh_timo;
+ mutex_exit(&sme->sme_mtx);
}
- goto out;
+ }
+ return error;
} else if (!obj) {
/*
@@ -1687,7 +1681,7 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
*/
obj = prop_dictionary_get(udict, "index");
if (!obj)
- goto out;
+ return EINVAL;
if (prop_object_type(obj) != PROP_TYPE_STRING) {
DPRINTF(("%s: 'index' not a string\n", __func__));
return EINVAL;
@@ -1695,8 +1689,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
} else
return EINVAL;
- /*
- * iterate over the sensors to find the right one.
+ /*
+ * Don't bother with locking when traversing the queue,
+ * the device is already marked as busy; if a sensor
+ * is going to be removed or added it will have to wait.
*/
TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
/*
@@ -1730,22 +1726,28 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
tdict = prop_array_get(array, i);
tobj =
prop_dictionary_get(tdict, "description");
- if (prop_string_equals(obj2, tobj))
- return EEXIST;
+ if (prop_string_equals(obj2, tobj)) {
+ error = EEXIST;
+ goto out;
+ }
}
/*
* Update the object in dictionary.
*/
+ mutex_enter(&sme->sme_mtx);
error = sme_sensor_upstring(dict,
"description",
blah);
- if (error)
- return error;
+ if (error) {
+ mutex_exit(&sme->sme_mtx);
+ goto out;
+ }
DPRINTF(("%s: sensor%d changed desc to: %s\n",
__func__, edata->sensor, blah));
edata->upropset |= USERPROP_DESC;
+ mutex_exit(&sme->sme_mtx);
}
/*
@@ -1755,12 +1757,16 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
targetfound = true;
if (edata->flags & ENVSYS_FCHANGERFACT) {
+ mutex_enter(&sme->sme_mtx);
edata->rfact = prop_number_integer_value(obj2);
edata->upropset |= USERPROP_RFACT;
+ mutex_exit(&sme->sme_mtx);
DPRINTF(("%s: sensor%d changed rfact to %d\n",
__func__, edata->sensor, edata->rfact));
- } else
- return ENOTSUP;
+ } else {
+ error = ENOTSUP;
+ goto out;
+ }
}
sdt = sme_get_description_table(SME_DESC_UNITS);
@@ -1779,8 +1785,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
targetfound = true;
if ((edata->flags & ENVSYS_FMONNOTSUPP) ||
- (edata->flags & ENVSYS_FPERCENT) == 0)
- return ENOTSUP;
+ (edata->flags & ENVSYS_FPERCENT) == 0) {
+ error = ENOTSUP;
+ goto out;
+ }
critval = prop_number_integer_value(obj2);
error = sme_event_register(dict,
@@ -1794,8 +1802,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
error = 0;
if (error)
goto out;
- else if (!error)
- edata->upropset |= USERPROP_BATTCAP;
+
+ mutex_enter(&sme->sme_mtx);
+ edata->upropset |= USERPROP_BATTCAP;
+ mutex_exit(&sme->sme_mtx);
}
/*
@@ -1805,8 +1815,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
targetfound = true;
if (edata->units == ENVSYS_INDICATOR ||
- edata->flags & ENVSYS_FMONNOTSUPP)
- return ENOTSUP;
+ edata->flags & ENVSYS_FMONNOTSUPP) {
+ error = ENOTSUP;
+ goto out;
+ }
critval = prop_number_integer_value(obj2);
error = sme_event_register(dict,
@@ -1820,8 +1832,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
error = 0;
if (error)
goto out;
- else if (!error)
- edata->upropset |= USERPROP_CRITMAX;
+
+ mutex_enter(&sme->sme_mtx);
+ edata->upropset |= USERPROP_CRITMAX;
+ mutex_exit(&sme->sme_mtx);
}
/*
@@ -1831,8 +1845,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
if (obj2 && prop_object_type(obj2) == PROP_TYPE_NUMBER) {
targetfound = true;
if (edata->units == ENVSYS_INDICATOR ||
- edata->flags & ENVSYS_FMONNOTSUPP)
- return ENOTSUP;
+ edata->flags & ENVSYS_FMONNOTSUPP) {
+ error = ENOTSUP;
+ goto out;
+ }
critval = prop_number_integer_value(obj2);
error = sme_event_register(dict,
@@ -1846,8 +1862,10 @@ sme_userset_dictionary(struct sysmon_envsys *sme, prop_dictionary_t udict,
error = 0;
if (error)
goto out;
- else if (!error)
- edata->upropset |= USERPROP_CRITMIN;
+
+ mutex_enter(&sme->sme_mtx);
+ edata->upropset |= USERPROP_CRITMIN;
+ mutex_exit(&sme->sme_mtx);
}
/*
diff --git a/sys/dev/sysmon/sysmon_envsys_events.c b/sys/dev/sysmon/sysmon_envsys_events.c
index d8f301dcd79..11087ac7cda 100644
--- a/sys/dev/sysmon/sysmon_envsys_events.c
+++ b/sys/dev/sysmon/sysmon_envsys_events.c
@@ -1,7 +1,7 @@
-/* $NetBSD: sysmon_envsys_events.c,v 1.50 2008/03/23 16:09:41 xtraeme Exp $ */
+/* $NetBSD: sysmon_envsys_events.c,v 1.51 2008/04/01 12:25:30 xtraeme Exp $ */
/*-
- * Copyright (c) 2007 Juan Romero Pardines.
+ * Copyright (c) 2007, 2008 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.50 2008/03/23 16:09:41 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.51 2008/04/01 12:25:30 xtraeme Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -62,7 +62,7 @@ static const struct sme_sensor_event sme_sensor_event[] = {
{ -1, -1 }
};
-static bool sysmon_low_power = false;
+static bool sysmon_low_power;
#define SME_EVTIMO (SME_EVENTS_DEFTIMEOUT * hz)
@@ -82,27 +82,34 @@ sme_event_register(prop_dictionary_t sdict, envsys_data_t *edata,
struct sysmon_envsys *sme, const char *objkey,
int32_t critval, int crittype, int powertype)
{
- sme_event_t *see = NULL;
+ sme_event_t *see = NULL, *osee = NULL;
prop_object_t obj;
bool critvalup = false;
int error = 0;
KASSERT(sdict != NULL || edata != NULL || sme != NULL);
- KASSERT(mutex_owned(&sme_mtx));
+ /*
+ * Allocate a new sysmon_envsys event.
+ */
+ see = kmem_zalloc(sizeof(*see), KM_SLEEP);
+ if (see == NULL)
+ return ENOMEM;
/*
* check if the event is already on the list and return
* EEXIST if value provided hasn't been changed.
*/
- LIST_FOREACH(see, &sme->sme_events_list, see_list) {
- if (strcmp(edata->desc, see->see_pes.pes_sensname) == 0)
- if (crittype == see->see_type) {
- if (see->see_critval == critval) {
+ mutex_enter(&sme->sme_mtx);
+ LIST_FOREACH(osee, &sme->sme_events_list, see_list) {
+ if (strcmp(edata->desc, osee->see_pes.pes_sensname) == 0)
+ if (crittype == osee->see_type) {
+ if (osee->see_critval == critval) {
DPRINTF(("%s: dev=%s sensor=%s type=%d "
"(already exists)\n", __func__,
- see->see_pes.pes_dvname,
- see->see_pes.pes_sensname,
- see->see_type));
+ osee->see_pes.pes_dvname,
+ osee->see_pes.pes_sensname,
+ osee->see_type));
+ mutex_exit(&sme->sme_mtx);
return EEXIST;
}
critvalup = true;
@@ -119,26 +126,21 @@ sme_event_register(prop_dictionary_t sdict, envsys_data_t *edata,
/*
* object is already in dictionary and value
* provided is not the same than we have
- * currently, update the critical value.
+ * currently, update the critical value.
*/
- see->see_critval = critval;
- DPRINTF(("%s: (%s) sensor=%s type=%d "
+ osee->see_critval = critval;
+ DPRINTF(("%s: (%s) event [sensor=%s type=%d] "
"(critval updated)\n", __func__, sme->sme_name,
- edata->desc, see->see_type));
+ edata->desc, osee->see_type));
error = sme_sensor_upint32(sdict, objkey, critval);
+ mutex_exit(&sme->sme_mtx);
return error;
}
}
- /*
- * The event is not in on the list or in a dictionary, create a new
- * sme event, assign required members and update the object in
- * the dictionary.
+ /*
+ * New event requested.
*/
- see = kmem_zalloc(sizeof(*see), KM_NOSLEEP);
- if (see == NULL)
- return ENOMEM;
-
see->see_edata = edata;
see->see_critval = critval;
see->see_type = crittype;
@@ -155,18 +157,17 @@ sme_event_register(prop_dictionary_t sdict, envsys_data_t *edata,
if (error)
goto out;
}
- DPRINTF(("%s: (%s) registering sensor=%s snum=%d type=%d "
- "critval=%" PRIu32 "\n", __func__,
+ DPRINTF(("%s: (%s) event registered (sensor=%s snum=%d type=%d "
+ "critval=%" PRIu32 ")\n", __func__,
see->see_sme->sme_name, see->see_pes.pes_sensname,
see->see_edata->sensor, see->see_type, see->see_critval));
/*
* Initialize the events framework if it wasn't initialized before.
*/
- mutex_enter(&sme_events_mtx);
if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0)
error = sme_events_init(sme);
- mutex_exit(&sme_events_mtx);
out:
+ mutex_exit(&sme->sme_mtx);
if (error)
kmem_free(see, sizeof(*see));
return error;
@@ -175,8 +176,7 @@ out:
/*
* sme_event_unregister_all:
*
- * + Unregisters all sysmon envsys events associated with a
- * sysmon envsys device.
+ * + Unregisters all events associated with a sysmon envsys device.
*/
void
sme_event_unregister_all(struct sysmon_envsys *sme)
@@ -184,10 +184,13 @@ sme_event_unregister_all(struct sysmon_envsys *sme)
sme_event_t *see;
int evcounter = 0;
- KASSERT(mutex_owned(&sme_mtx));
KASSERT(sme != NULL);
+ mutex_enter(&sme->sme_mtx);
LIST_FOREACH(see, &sme->sme_events_list, see_list) {
+ while (see->see_flags & SME_EVENT_WORKING)
+ cv_wait(&sme->sme_condvar, &sme->sme_mtx);
+
if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0)
evcounter++;
}
@@ -200,25 +203,19 @@ sme_event_unregister_all(struct sysmon_envsys *sme)
break;
if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0) {
+ LIST_REMOVE(see, see_list);
DPRINTF(("%s: event %s %d removed (%s)\n", __func__,
see->see_pes.pes_sensname, see->see_type,
sme->sme_name));
-
- while (see->see_flags & SME_EVENT_WORKING)
- cv_wait(&sme_cv, &sme_mtx);
-
- LIST_REMOVE(see, see_list);
kmem_free(see, sizeof(*see));
evcounter--;
}
}
- if (LIST_EMPTY(&sme->sme_events_list)) {
- mutex_enter(&sme_events_mtx);
+ if (LIST_EMPTY(&sme->sme_events_list))
if (sme->sme_flags & SME_CALLOUT_INITIALIZED)
sme_events_destroy(sme);
- mutex_exit(&sme_events_mtx);
- }
+ mutex_exit(&sme->sme_mtx);
}
/*
@@ -232,9 +229,9 @@ sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type)
sme_event_t *see;
bool found = false;
- KASSERT(mutex_owned(&sme_mtx));
KASSERT(sensor != NULL);
+ mutex_enter(&sme->sme_mtx);
LIST_FOREACH(see, &sme->sme_events_list, see_list) {
if (strcmp(see->see_pes.pes_sensname, sensor) == 0) {
if (see->see_type == type) {
@@ -244,13 +241,19 @@ sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type)
}
}
- if (!found)
+ if (!found) {
+ mutex_exit(&sme->sme_mtx);
return EINVAL;
+ }
+ /*
+ * Wait for the event to finish its work, remove from the list
+ * and release resouces.
+ */
while (see->see_flags & SME_EVENT_WORKING)
- cv_wait(&sme_cv, &sme_mtx);
+ cv_wait(&sme->sme_condvar, &sme->sme_mtx);
- DPRINTF(("%s: removing dev=%s sensor=%s type=%d\n",
+ DPRINTF(("%s: removed dev=%s sensor=%s type=%d\n",
__func__, see->see_pes.pes_dvname, sensor, type));
LIST_REMOVE(see, see_list);
/*
@@ -259,11 +262,9 @@ sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type)
* - stop and destroy the callout.
* - destroy the workqueue.
*/
- if (LIST_EMPTY(&sme->sme_events_list)) {
- mutex_enter(&sme_events_mtx);
+ if (LIST_EMPTY(&sme->sme_events_list))
sme_events_destroy(sme);
- mutex_exit(&sme_events_mtx);
- }
+ mutex_exit(&sme->sme_mtx);
kmem_free(see, sizeof(*see));
return 0;
@@ -288,7 +289,6 @@ do { \
if (sed_t->sed_edata->flags & (a)) { \
char str[ENVSYS_DESCLEN] = "monitoring-state-"; \
\
- sysmon_envsys_acquire(sed_t->sed_sme); \
error = sme_event_register(sed_t->sed_sdict, \
sed_t->sed_edata, \
sed_t->sed_sme, \
@@ -307,11 +307,9 @@ do { \
str, \
true); \
} \
- sysmon_envsys_release(sed_t->sed_sme); \
} \
} while (/* CONSTCOND */ 0)
- mutex_enter(&sme_mtx);
SEE_REGEVENT(ENVSYS_FMONCRITICAL,
PENVSYS_EVENT_CRITICAL,
"critical");
@@ -335,7 +333,6 @@ do { \
SEE_REGEVENT(ENVSYS_FMONSTCHANGED,
PENVSYS_EVENT_STATE_CHANGED,
"state-changed");
- mutex_exit(&sme_mtx);
/*
* we are done, free memory now.
@@ -351,11 +348,11 @@ do { \
int
sme_events_init(struct sysmon_envsys *sme)
{
- int error;
+ int error = 0;
uint64_t timo;
KASSERT(sme != NULL);
- KASSERT(mutex_owned(&sme_events_mtx));
+ KASSERT(mutex_owned(&sme->sme_mtx));
if (sme->sme_events_timeout)
timo = sme->sme_events_timeout * hz;
@@ -365,42 +362,42 @@ sme_events_init(struct sysmon_envsys *sme)
error = workqueue_create(&sme->sme_wq, sme->sme_name,
sme_events_worker, sme, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE);
if (error)
- goto out;
+ return error;
+ mutex_init(&sme->sme_callout_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
callout_setfunc(&sme->sme_callout, sme_events_check, sme);
callout_schedule(&sme->sme_callout, timo);
sme->sme_flags |= SME_CALLOUT_INITIALIZED;
DPRINTF(("%s: events framework initialized for '%s'\n",
__func__, sme->sme_name));
-out:
return error;
}
/*
* sme_events_destroy:
*
- * + Destroys the events framework for this device: the callout
- * is stopped and its workqueue is destroyed because the queue
- * is empty.
+ * + Destroys the event framework for this device: callout
+ * stopped, workqueue destroyed and callout mutex destroyed.
*/
void
sme_events_destroy(struct sysmon_envsys *sme)
{
- KASSERT(mutex_owned(&sme_events_mtx));
+ KASSERT(mutex_owned(&sme->sme_mtx));
callout_stop(&sme->sme_callout);
sme->sme_flags &= ~SME_CALLOUT_INITIALIZED;
DPRINTF(("%s: events framework destroyed for '%s'\n",
__func__, sme->sme_name));
workqueue_destroy(sme->sme_wq);
+ mutex_destroy(&sme->sme_callout_mtx);
}
/*
* sme_events_check:
*
- * + Runs the work on the passed sysmon envsys device for all
- * registered events.
+ * + Passes the events to the workqueue thread and stops
+ * the callout if the 'low-power' condition is triggered.
*/
void
sme_events_check(void *arg)
@@ -411,33 +408,25 @@ sme_events_check(void *arg)
KASSERT(sme != NULL);
- mutex_enter(&sme_callout_mtx);
-
- LIST_FOREACH(see, &sme->sme_events_list, see_list)
+ mutex_enter(&sme->sme_callout_mtx);
+ LIST_FOREACH(see, &sme->sme_events_list, see_list) {
workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL);
-
- /*
- * Now that the events list was checked, reset the refresh value.
- */
- LIST_FOREACH(see, &sme->sme_events_list, see_list)
see->see_flags &= ~SME_EVENT_REFRESHED;
-
+ }
if (sme->sme_events_timeout)
timo = sme->sme_events_timeout * hz;
else
timo = SME_EVTIMO;
-
if (!sysmon_low_power)
callout_schedule(&sme->sme_callout, timo);
-
- mutex_exit(&sme_callout_mtx);
+ mutex_exit(&sme->sme_callout_mtx);
}
/*
* sme_events_worker:
*
* + workqueue thread that checks if there's a critical condition
- * and sends an event if the condition was triggered.
+ * and sends an event if it was triggered.
*/
void
sme_events_worker(struct work *wk, void *arg)
@@ -445,18 +434,16 @@ sme_events_worker(struct work *wk, void *arg)
const struct sme_description_table *sdt = NULL;
const struct sme_sensor_event *sse = sme_sensor_event;
sme_event_t *see = (void *)wk;
- struct sysmon_envsys *sme;
- int i, state, error;
+ struct sysmon_envsys *sme = see->see_sme;
+ envsys_data_t *edata = see->see_edata;
+ int i, state = 0;
KASSERT(wk == &see->see_wk);
- KASSERT(see != NULL);
-
- state = error = 0;
-
- mutex_enter(&sme_mtx);
- see->see_flags |= SME_EVENT_WORKING;
- sme = see->see_sme;
+ KASSERT(sme != NULL || edata != NULL);
+ mutex_enter(&sme->sme_mtx);
+ if ((see->see_flags & SME_EVENT_WORKING) == 0)
+ see->see_flags |= SME_EVENT_WORKING;
/*
* refresh the sensor that was marked with a critical event
* only if it wasn't refreshed before or if the driver doesn't
@@ -464,18 +451,18 @@ sme_events_worker(struct work *wk, void *arg)
*/
if ((sme->sme_flags & SME_DISABLE_REFRESH) == 0) {
if ((see->see_flags & SME_EVENT_REFRESHED) == 0) {
- (*sme->sme_refresh)(sme, see->see_edata);
+ /* refresh sensor in device */
+ (*sme->sme_refresh)(sme, edata);
see->see_flags |= SME_EVENT_REFRESHED;
}
}
DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d state=%d units=%d "
- "value_cur=%d\n", __func__, sme->sme_name, see->see_edata->desc,
- see->see_edata->sensor, see->see_edata->state,
- see->see_edata->units, see->see_edata->value_cur));
+ "value_cur=%d\n", __func__, sme->sme_name, edata->desc,
+ edata->sensor, edata->state, edata->units, edata->value_cur));
/* skip the event if current sensor is in invalid state */
- if (see->see_edata->state == ENVSYS_SINVALID)
+ if (edata->state == ENVSYS_SINVALID)
goto out;
#define SME_SEND_NORMALEVENT() \
@@ -505,10 +492,13 @@ do { \
if (sse[i].event == see->see_type)
break;
- if (see->see_evsent && see->see_edata->state == ENVSYS_SVALID)
+ if (sse[i].state == -1)
+ break;
+
+ if (see->see_evsent && edata->state == ENVSYS_SVALID)
SME_SEND_NORMALEVENT();
- if (!see->see_evsent && see->see_edata->state == sse[i].state)
+ if (!see->see_evsent && edata->state == sse[i].state)
SME_SEND_EVENT(see->see_type);
break;
@@ -517,12 +507,10 @@ do { \
*/
case PENVSYS_EVENT_BATT_USERCAP:
case PENVSYS_EVENT_USER_CRITMIN:
- if (see->see_evsent &&
- see->see_edata->value_cur > see->see_critval)
+ if (see->see_evsent && edata->value_cur > see->see_critval)
SME_SEND_NORMALEVENT();
- if (!see->see_evsent &&
- see->see_edata->value_cur < see->see_critval)
+ if (!see->see_evsent && edata->value_cur < see->see_critval)
SME_SEND_EVENT(see->see_type);
break;
@@ -530,12 +518,10 @@ do { \
* if value_cur is higher than the limit, send the event...
*/
case PENVSYS_EVENT_USER_CRITMAX:
- if (see->see_evsent &&
- see->see_edata->value_cur < see->see_critval)
+ if (see->see_evsent && edata->value_cur < see->see_critval)
SME_SEND_NORMALEVENT();
- if (!see->see_evsent &&
- see->see_edata->value_cur > see->see_critval)
+ if (!see->see_evsent && edata->value_cur > see->see_critval)
SME_SEND_EVENT(see->see_type);
break;
@@ -547,17 +533,17 @@ do { \
/*
* the state has not been changed, just ignore the event.
*/
- if (see->see_edata->value_cur == see->see_evsent)
+ if (edata->value_cur == see->see_evsent)
break;
- switch (see->see_edata->units) {
+ switch (edata->units) {
case ENVSYS_DRIVE:
sdt = sme_get_description_table(SME_DESC_DRIVE_STATES);
state = ENVSYS_DRIVE_ONLINE;
break;
case ENVSYS_BATTERY_CAPACITY:
- sdt =
- sme_get_description_table(SME_DESC_BATTERY_CAPACITY);
+ sdt = sme_get_description_table(
+ SME_DESC_BATTERY_CAPACITY);
state = ENVSYS_BATTERY_CAPACITY_NORMAL;
break;
default:
@@ -566,9 +552,12 @@ do { \
}
for (i = 0; sdt[i].type != -1; i++)
- if (sdt[i].type == see->see_edata->value_cur)
+ if (sdt[i].type == edata->value_cur)
break;
+ if (sdt[i].type == -1)
+ break;
+
/*
* copy current state description.
*/
@@ -578,24 +567,24 @@ do { \
/*
* state is ok again... send a normal event.
*/
- if (see->see_evsent && see->see_edata->value_cur == state)
+ if (see->see_evsent && edata->value_cur == state)
SME_SEND_NORMALEVENT();
/*
* state has been changed... send event.
*/
- if (see->see_evsent || see->see_edata->value_cur != state) {
+ if (see->see_evsent || edata->value_cur != state) {
/*
* save current drive state.
*/
- see->see_evsent = see->see_edata->value_cur;
+ see->see_evsent = edata->value_cur;
sysmon_penvsys_event(&see->see_pes, see->see_type);
}
/*
* There's no need to continue if it's a drive sensor.
*/
- if (see->see_edata->units == ENVSYS_DRIVE)
+ if (edata->units == ENVSYS_DRIVE)
break;
/*
@@ -619,25 +608,27 @@ do { \
out:
see->see_flags &= ~SME_EVENT_WORKING;
- cv_broadcast(&sme_cv);
- mutex_exit(&sme_mtx);
+ cv_broadcast(&sme->sme_condvar);
+ mutex_exit(&sme->sme_mtx);
}
/*
- * Returns true if the system is in low power state: all AC adapters
- * are OFF and all batteries are in LOW/CRITICAL state.
+ * Returns true if the system is in low power state: an AC adapter
+ * is OFF and all batteries are in LOW/CRITICAL state.
*/
static bool
sme_event_check_low_power(void)
{
- KASSERT(mutex_owned(&sme_mtx));
-
if (!sme_acadapter_check())
return false;
return sme_battery_check();
}
+/*
+ * Called with the sysmon_envsys device mtx held through the
+ * workqueue thread.
+ */
static bool
sme_acadapter_check(void)
{
@@ -645,19 +636,19 @@ sme_acadapter_check(void)
envsys_data_t *edata;
bool dev = false, sensor = false;
- KASSERT(mutex_owned(&sme_mtx));
-
LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
if (sme->sme_class == SME_CLASS_ACADAPTER) {
dev = true;
break;
}
}
+
/*
* No AC Adapter devices were found.
*/
if (!dev)
return false;
+
/*
* Check if there's an AC adapter device connected.
*/
@@ -670,12 +661,20 @@ sme_acadapter_check(void)
return false;
}
}
+
if (!sensor)
return false;
+ /*
+ * AC adapter found and not connected.
+ */
return true;
}
+/*
+ * Called with the sysmon_envsys device mtx held through the
+ * workqueue thread.
+ */
static bool
sme_battery_check(void)
{
@@ -683,8 +682,6 @@ sme_battery_check(void)
envsys_data_t *edata;
bool battery, batterycap, batterycharge;
- KASSERT(mutex_owned(&sme_mtx));
-
battery = batterycap = batterycharge = false;
/*
@@ -710,6 +707,7 @@ sme_battery_check(void)
}
}
}
+
if (!battery || !batterycap || !batterycharge)
return false;
@@ -722,8 +720,6 @@ sme_battery_check(void)
static bool
sme_battery_critical(envsys_data_t *edata)
{
- KASSERT(mutex_owned(&sme_mtx));
-
if (edata->value_cur == ENVSYS_BATTERY_CAPACITY_CRITICAL ||
edata->value_cur == ENVSYS_BATTERY_CAPACITY_LOW)
return true;
diff --git a/sys/dev/sysmon/sysmon_envsysvar.h b/sys/dev/sysmon/sysmon_envsysvar.h
index d37f1e4806f..ef726fad052 100644
--- a/sys/dev/sysmon/sysmon_envsysvar.h
+++ b/sys/dev/sysmon/sysmon_envsysvar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: sysmon_envsysvar.h,v 1.26 2007/11/20 17:24:32 xtraeme Exp $ */
+/* $NetBSD: sysmon_envsysvar.h,v 1.27 2008/04/01 12:25:30 xtraeme Exp $ */
/*-
- * Copyright (c) 2007 Juan Romero Pardines.
+ * Copyright (c) 2007, 2008 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@ struct sme_sensor_names {
* struct used by a sysmon envsys event.
*/
typedef struct sme_event {
- struct work see_wk;
+ struct work see_wk;
LIST_ENTRY(sme_event) see_list;
struct sysmon_envsys *see_sme; /* device associated */
struct penvsys_state see_pes; /* our power envsys */
@@ -109,10 +109,7 @@ struct sme_description_table {
/*
* common stuff.
*/
-extern kmutex_t sme_mtx; /* mutex for devices/events */
-extern kmutex_t sme_events_mtx; /* to init/destroy the events layer */
-extern kmutex_t sme_callout_mtx; /* for the callouts */
-extern kcondvar_t sme_cv; /* to wait for devices/events working */
+extern kmutex_t sme_global_mtx; /* for the sme linked list and dict */
/*
* linked list for the sysmon envsys devices.
@@ -131,8 +128,8 @@ int sme_userset_dictionary(struct sysmon_envsys *,
prop_dictionary_t, prop_array_t);
prop_dictionary_t sme_sensor_dictionary_get(prop_array_t, const char *);
struct sysmon_envsys *sysmon_envsys_find(const char *);
-void sysmon_envsys_acquire(struct sysmon_envsys *);
-void sysmon_envsys_release(struct sysmon_envsys *);
+void sysmon_envsys_acquire(struct sysmon_envsys *, bool);
+void sysmon_envsys_release(struct sysmon_envsys *, bool);
/*
* functions to handle sysmon envsys events.
@@ -146,7 +143,7 @@ void sme_event_drvadd(void *);
int sme_events_init(struct sysmon_envsys *);
void sme_events_destroy(struct sysmon_envsys *);
void sme_events_check(void *);
-void sme_events_worker(struct work *, void *);
+void sme_events_worker(struct work *, void *);
/*
* common functions to create/update objects in a dictionary.
diff --git a/sys/dev/sysmon/sysmonvar.h b/sys/dev/sysmon/sysmonvar.h
index 5d769309f65..26863629679 100644
--- a/sys/dev/sysmon/sysmonvar.h
+++ b/sys/dev/sysmon/sysmonvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: sysmonvar.h,v 1.24 2008/03/23 16:09:41 xtraeme Exp $ */
+/* $NetBSD: sysmonvar.h,v 1.25 2008/04/01 12:25:30 xtraeme Exp $ */
/*-
* Copyright (c) 2000 Zembu Labs, Inc.
@@ -40,13 +40,15 @@
#include <sys/wdog.h>
#include <sys/power.h>
#include <sys/queue.h>
-#include <sys/callout.h>
-#include <sys/workqueue.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
struct lwp;
struct proc;
struct knote;
struct uio;
+struct workqueue;
+struct callout;
#define SYSMON_MINOR_ENVSYS 0
#define SYSMON_MINOR_WDOG 1
@@ -100,6 +102,13 @@ struct sysmon_envsys {
* tailq for the sensors that a device maintains.
*/
TAILQ_HEAD(, envsys_data) sme_sensors_list;
+
+ /*
+ * Locking/synchronization.
+ */
+ kmutex_t sme_mtx;
+ kmutex_t sme_callout_mtx;
+ kcondvar_t sme_condvar;
};
int sysmonopen_envsys(dev_t, int, int, struct lwp *);