diff options
| author | xtraeme <xtraeme@NetBSD.org> | 2008-04-01 12:25:30 +0000 |
|---|---|---|
| committer | xtraeme <xtraeme@NetBSD.org> | 2008-04-01 12:25:30 +0000 |
| commit | 5ee4eba88daa5874d8a4b2663c986fff47abe941 (patch) | |
| tree | 3c418f77527c6d347b5aae300b820e69fcd0d2c3 /sys/dev/sysmon | |
| parent | e9c68c5df07731f273526cca51b211c80704e6d1 (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.c | 408 | ||||
| -rw-r--r-- | sys/dev/sysmon/sysmon_envsys_events.c | 238 | ||||
| -rw-r--r-- | sys/dev/sysmon/sysmon_envsysvar.h | 17 | ||||
| -rw-r--r-- | sys/dev/sysmon/sysmonvar.h | 15 |
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 *); |
