Index: sys/dev/sysmon/sysmon_envsys.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/sysmon_envsys.c,v
retrieving revision 1.143
diff -p -u -r1.143 sysmon_envsys.c
--- sys/dev/sysmon/sysmon_envsys.c      26 May 2018 21:15:46 -0000      1.143
+++ sys/dev/sysmon/sysmon_envsys.c      26 Nov 2018 23:17:24 -0000
@@ -84,12 +84,17 @@ __KERNEL_RCSID(0, "$NetBSD: sysmon_envsy
#include <dev/sysmon/sysmon_envsysvar.h>
#include <dev/sysmon/sysmon_taskq.h>

-kmutex_t sme_global_mtx;
+static kmutex_t sme_global_mtx;
+static kcondvar_t sme_global_cv;
+static bool sme_global_busy;

prop_dictionary_t sme_propd;

struct sysmon_envsys_lh sysmon_envsys_list;

+static int sysmon_envsys_lock(bool);
+static void sysmon_envsys_unlock(void);
+
static uint32_t sysmon_envsys_next_sensor_index;
static struct sysmon_envsys *sysmon_envsys_find_40(u_int);

@@ -118,6 +123,7 @@ sme_preinit(void)

       LIST_INIT(&sysmon_envsys_list);
       mutex_init(&sme_global_mtx, MUTEX_DEFAULT, IPL_NONE);
+       cv_init(&sme_global_cv, "smeglobal");
       sme_propd = prop_dictionary_create();

       return 0;
@@ -150,14 +156,45 @@ sysmon_envsys_fini(void)
       else
               error = sysmon_attach_minor(SYSMON_MINOR_ENVSYS, NULL);

-       if (error == 0)
+       if (error == 0) {
+               cv_destroy(&sme_global_cv);
               mutex_destroy(&sme_global_mtx);
+       }

       // XXX: prop_dictionary ???

       return error;
}

+static int
+sysmon_envsys_lock(bool sig)
+{
+       int error = 0;
+
+       mutex_enter(&sme_global_mtx);
+       while (sme_global_busy && !error) {
+               if (sig)
+                       error = cv_wait_sig(&sme_global_cv, &sme_global_mtx);
+               else
+                       cv_wait(&sme_global_cv, &sme_global_mtx);
+       }
+       if (!error)
+               sme_global_busy = true;
+       mutex_exit(&sme_global_mtx);
+
+       return error;
+}
+
+static void
+sysmon_envsys_unlock(void)
+{
+
+       mutex_enter(&sme_global_mtx);
+       sme_global_busy = false;
+       cv_signal(&sme_global_cv);
+       mutex_exit(&sme_global_mtx);
+}
+
/*
 * sysmonopen_envsys:
 *
@@ -204,7 +241,8 @@ sysmonioctl_envsys(dev_t dev, u_long cmd
                * Update dictionaries on all sysmon envsys devices
                * registered.
                */
-               mutex_enter(&sme_global_mtx);
+               if ((error = sysmon_envsys_lock(true)) != 0)
+                       break;
               LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
                       sysmon_envsys_acquire(sme, false);
                       error = sme_update_dictionary(sme);
@@ -212,12 +250,12 @@ sysmonioctl_envsys(dev_t dev, u_long cmd
                               DPRINTF(("%s: sme_update_dictionary, "
                                   "error=%d\n", __func__, error));
                               sysmon_envsys_release(sme, false);
-                               mutex_exit(&sme_global_mtx);
+                               sysmon_envsys_unlock();
                               return error;
                       }
                       sysmon_envsys_release(sme, false);
               }
-               mutex_exit(&sme_global_mtx);
+               sysmon_envsys_unlock();
               /*
                * Copy global dictionary to userland.
                */
@@ -402,9 +440,9 @@ sysmonioctl_envsys(dev_t dev, u_long cmd

               if (tred->sensor < sme->sme_nsensors) {
                       if ((sme->sme_flags & SME_POLL_ONLY) == 0) {
-                               mutex_enter(&sme->sme_mtx);
+                               sysmon_envsys_acquire(sme, false);
                               sysmon_envsys_refresh_sensor(sme, edata);
-                               mutex_exit(&sme->sme_mtx);
+                               sysmon_envsys_release(sme, false);
                       }

                       /*
@@ -531,7 +569,6 @@ sysmon_envsys_create(void)
       TAILQ_INIT(&sme->sme_sensors_list);
       LIST_INIT(&sme->sme_events_list);
       mutex_init(&sme->sme_mtx, MUTEX_DEFAULT, IPL_NONE);
-       mutex_init(&sme->sme_work_mtx, MUTEX_DEFAULT, IPL_NONE);
       cv_init(&sme->sme_condvar, "sme_wait");

       return sme;
@@ -555,7 +592,6 @@ sysmon_envsys_destroy(struct sysmon_envs
               TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
       }
       mutex_destroy(&sme->sme_mtx);
-       mutex_destroy(&sme->sme_work_mtx);
       cv_destroy(&sme->sme_condvar);
       kmem_free(sme, sizeof(*sme));
}
@@ -587,12 +623,10 @@ sysmon_envsys_sensor_attach(struct sysmo
       if (strlen(edata->desc) == 0)
               return EINVAL;

-       mutex_enter(&sme->sme_mtx);
-       sysmon_envsys_acquire(sme, true);
+       sysmon_envsys_acquire(sme, false);
       TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
               if (strcmp(oedata->desc, edata->desc) == 0) {
-                       sysmon_envsys_release(sme, true);
-                       mutex_exit(&sme->sme_mtx);
+                       sysmon_envsys_release(sme, false);
                       return EEXIST;
               }
       }
@@ -606,8 +640,7 @@ sysmon_envsys_sensor_attach(struct sysmo
        */
       edata->sensor = sme->sme_nsensors;
       sme->sme_nsensors++;
-       sysmon_envsys_release(sme, true);
-       mutex_exit(&sme->sme_mtx);
+       sysmon_envsys_release(sme, false);

       DPRINTF(("%s: attached #%d (%s), units=%d (%s)\n",
           __func__, edata->sensor, edata->desc,
@@ -634,8 +667,7 @@ sysmon_envsys_sensor_detach(struct sysmo
       /*
        * Check the sensor is already on the list.
        */
-       mutex_enter(&sme->sme_mtx);
-       sysmon_envsys_acquire(sme, true);
+       sysmon_envsys_acquire(sme, false);
       TAILQ_FOREACH(oedata, &sme->sme_sensors_list, sensors_head) {
               if (oedata->sensor == edata->sensor) {
                       found = true;
@@ -644,8 +676,7 @@ sysmon_envsys_sensor_detach(struct sysmo
       }

       if (!found) {
-               sysmon_envsys_release(sme, true);
-               mutex_exit(&sme->sme_mtx);
+               sysmon_envsys_release(sme, false);
               return EINVAL;
       }

@@ -662,8 +693,7 @@ sysmon_envsys_sensor_detach(struct sysmo
       }
       TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
       sme->sme_nsensors--;
-       sysmon_envsys_release(sme, true);
-       mutex_exit(&sme->sme_mtx);
+       sysmon_envsys_release(sme, false);

       if (destroy)
               sme_events_destroy(sme);
@@ -705,14 +735,15 @@ sysmon_envsys_register(struct sysmon_env
        * Check if requested sysmon_envsys device is valid
        * and does not exist already in the list.
        */
-       mutex_enter(&sme_global_mtx);
+       if ((error = sysmon_envsys_lock(true)) != 0)
+               return error;
       LIST_FOREACH(lsme, &sysmon_envsys_list, sme_list) {
              if (strcmp(lsme->sme_name, sme->sme_name) == 0) {
-                       mutex_exit(&sme_global_mtx);
+                       sysmon_envsys_unlock();
                       return EEXIST;
              }
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();

       /*
        * sanity check: if SME_DISABLE_REFRESH is not set,
@@ -797,10 +828,13 @@ sysmon_envsys_register(struct sysmon_env
        *      <array>
        *              ...
        */
-       mutex_enter(&sme_global_mtx);
+       if ((error = sysmon_envsys_lock(true)) != 0) {
+               DPRINTF(("%s: global dictionary lock aborted\n", __func__));
+               goto out;
+       }
       if (!prop_dictionary_set(sme_propd, sme->sme_name, array)) {
               error = EINVAL;
-               mutex_exit(&sme_global_mtx);
+               sysmon_envsys_unlock();
               DPRINTF(("%s: prop_dictionary_set for '%s'\n", __func__,
                   sme->sme_name));
               goto out;
@@ -812,7 +846,7 @@ sysmon_envsys_register(struct sysmon_env
       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;
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();

out:
       /*
@@ -984,14 +1018,14 @@ sysmon_envsys_unregister(struct sysmon_e
        * for remaining devices in the list (only used for compatibility
        * with previous API), and remove the device from the list.
        */
-       mutex_enter(&sme_global_mtx);
+       sysmon_envsys_lock(false);
       sysmon_envsys_next_sensor_index -= sme->sme_nsensors;
       LIST_FOREACH(osme, &sysmon_envsys_list, sme_list) {
               if (osme->sme_fsensor >= sme->sme_fsensor)
                       osme->sme_fsensor -= sme->sme_nsensors;
       }
       LIST_REMOVE(sme, sme_list);
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();

       TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) {
               sysmon_envsys_sensor_detach(sme, edata);
@@ -1007,9 +1041,9 @@ sysmon_envsys_unregister(struct sysmon_e
        */
       array = prop_dictionary_get(sme_propd, sme->sme_name);
       if (array && prop_object_type(array) == PROP_TYPE_ARRAY) {
-               mutex_enter(&sme_global_mtx);
+               sysmon_envsys_lock(false);
               prop_dictionary_remove(sme_propd, sme->sme_name);
-               mutex_exit(&sme_global_mtx);
+               sysmon_envsys_unlock();
               sysmon_envsys_destroy_plist(array);
       }
       /*
@@ -1029,14 +1063,14 @@ sysmon_envsys_find(const char *name)
{
       struct sysmon_envsys *sme;

-       mutex_enter(&sme_global_mtx);
+       sysmon_envsys_lock(false);
       LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
               if (strcmp(sme->sme_name, name) == 0) {
                       sysmon_envsys_acquire(sme, false);
                       break;
               }
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();

       return sme;
}
@@ -1049,7 +1083,7 @@ sysmon_envsys_find_40(u_int idx)
{
       struct sysmon_envsys *sme;

-       mutex_enter(&sme_global_mtx);
+       sysmon_envsys_lock(false);
       LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
               if (idx >= sme->sme_fsensor &&
                   idx < (sme->sme_fsensor + sme->sme_nsensors)) {
@@ -1057,7 +1091,7 @@ sysmon_envsys_find_40(u_int idx)
                       break;
               }
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();

       return sme;
}
@@ -1074,6 +1108,7 @@ sysmon_envsys_acquire(struct sysmon_envs
       KASSERT(sme != NULL);

       if (locked) {
+               KASSERT(mutex_owned(&sme->sme_mtx));
               while (sme->sme_flags & SME_FLAG_BUSY)
                       cv_wait(&sme->sme_condvar, &sme->sme_mtx);
               sme->sme_flags |= SME_FLAG_BUSY;
@@ -1098,6 +1133,7 @@ sysmon_envsys_release(struct sysmon_envs
       KASSERT(sme != NULL);

       if (locked) {
+               KASSERT(mutex_owned(&sme->sme_mtx));
               sme->sme_flags &= ~SME_FLAG_BUSY;
               cv_broadcast(&sme->sme_condvar);
       } else {
@@ -1121,12 +1157,10 @@ sme_initial_refresh(void *arg)
       struct sysmon_envsys *sme = arg;
       envsys_data_t *edata;

-       mutex_enter(&sme->sme_mtx);
-       sysmon_envsys_acquire(sme, true);
+       sysmon_envsys_acquire(sme, false);
       TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head)
               sysmon_envsys_refresh_sensor(sme, edata);
-       sysmon_envsys_release(sme, true);
-       mutex_exit(&sme->sme_mtx);
+       sysmon_envsys_release(sme, false);
}

/*
@@ -1178,7 +1212,7 @@ sme_remove_userprops(void)
       uint32_t props;
       int ptype;

-       mutex_enter(&sme_global_mtx);
+       sysmon_envsys_lock(false);
       LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
               sysmon_envsys_acquire(sme, false);
               array = prop_dictionary_get(sme_propd, sme->sme_name);
@@ -1336,7 +1370,7 @@ sme_remove_userprops(void)
               sysmon_envsys_release(sme, true);
               mutex_exit(&sme->sme_mtx);
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();
}

/*
@@ -1550,7 +1584,7 @@ sysmon_envsys_get_max_value(bool (*predi
       uint32_t maxv, v;

       maxv = 0;
-       mutex_enter(&sme_global_mtx);
+       sysmon_envsys_lock(false);
       LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {
               sysmon_envsys_acquire(sme, false);
               v = sme_get_max_value(sme, predicate, refresh);
@@ -1558,7 +1592,7 @@ sysmon_envsys_get_max_value(bool (*predi
               if (v > maxv)
                       maxv = v;
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();
       return maxv;
}

@@ -1581,9 +1615,9 @@ sme_get_max_value(struct sysmon_envsys *
               /*
                * refresh sensor data
                */
-               mutex_enter(&sme->sme_mtx);
+               sysmon_envsys_acquire(sme, false);
               sysmon_envsys_refresh_sensor(sme, edata);
-               mutex_exit(&sme->sme_mtx);
+               sysmon_envsys_release(sme, false);

               v = edata->value_cur;
               if (v > maxv)
@@ -1655,9 +1689,7 @@ sme_update_dictionary(struct sysmon_envs
               /*
                * refresh sensor data via sme_envsys_refresh_sensor
                */
-               mutex_enter(&sme->sme_mtx);
               sysmon_envsys_refresh_sensor(sme, edata);
-               mutex_exit(&sme->sme_mtx);

               /*
                * retrieve sensor's dictionary.
@@ -1923,19 +1955,17 @@ sme_userset_dictionary(struct sysmon_env
                       /*
                        * Update the object in dictionary.
                        */
-                       mutex_enter(&sme->sme_mtx);
                       error = sme_sensor_upstring(dict,
                                                   "description",
                                                   blah);
                       if (error) {
-                               mutex_exit(&sme->sme_mtx);
+                               sysmon_envsys_release(sme, false);
                               goto out;
                       }

                       DPRINTF(("%s: sensor%d changed desc to: %s\n",
                           __func__, edata->sensor, blah));
                       edata->upropset |= PROP_DESC;
-                       mutex_exit(&sme->sme_mtx);
               }

               /*
@@ -1945,10 +1975,8 @@ sme_userset_dictionary(struct sysmon_env
               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 |= PROP_RFACT;
-                               mutex_exit(&sme->sme_mtx);
                               DPRINTF(("%s: sensor%d changed rfact to %d\n",
                                   __func__, edata->sensor, edata->rfact));
                       } else {
@@ -2086,22 +2114,23 @@ sysmon_envsys_foreach_sensor(sysmon_envs
       struct sysmon_envsys *sme;
       envsys_data_t *sensor;

-       mutex_enter(&sme_global_mtx);
+       if (sysmon_envsys_lock(true))
+               return;
       LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) {

               sysmon_envsys_acquire(sme, false);
               TAILQ_FOREACH(sensor, &sme->sme_sensors_list, sensors_head) {
                       if (refresh) {
-                               mutex_enter(&sme->sme_mtx);
+                               sysmon_envsys_acquire(sme, false);
                               sysmon_envsys_refresh_sensor(sme, sensor);
-                               mutex_exit(&sme->sme_mtx);
+                               sysmon_envsys_release(sme, false);
                       }
                       if (!(*func)(sme, sensor, arg))
                               break;
               }
               sysmon_envsys_release(sme, false);
       }
-       mutex_exit(&sme_global_mtx);
+       sysmon_envsys_unlock();
}

/*
Index: sys/dev/sysmon/sysmon_envsys_events.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/sysmon_envsys_events.c,v
retrieving revision 1.121
diff -p -u -r1.121 sysmon_envsys_events.c
--- sys/dev/sysmon/sysmon_envsys_events.c       11 Sep 2017 06:02:09 -0000      1.121
+++ sys/dev/sysmon/sysmon_envsys_events.c       26 Nov 2018 23:17:24 -0000
@@ -169,7 +169,7 @@ sme_event_register(prop_dictionary_t sdi
        * check if the event is already on the list and return
        * EEXIST if value provided hasn't been changed.
        */
-       mutex_enter(&sme->sme_mtx);
+       sysmon_envsys_acquire(sme, false);
       LIST_FOREACH(osee, &sme->sme_events_list, see_list) {
               if (strcmp(edata->desc, osee->see_pes.pes_sensname) != 0)
                       continue;
@@ -221,7 +221,7 @@ sme_event_register(prop_dictionary_t sdi
               break;
       }
       if (crittype == PENVSYS_EVENT_NULL && see != NULL) {
-               mutex_exit(&sme->sme_mtx);
+               sysmon_envsys_release(sme, false);
               return EEXIST;
       }

@@ -328,7 +328,7 @@ out:
       if ((error == 0 || error == EEXIST) && osee == NULL)
               LIST_INSERT_HEAD(&sme->sme_events_list, see, see_list);

-       mutex_exit(&sme->sme_mtx);
+       sysmon_envsys_release(sme, false);

       return error;
}
@@ -561,7 +561,6 @@ sme_events_init(struct sysmon_envsys *sm
       int error = 0;

       KASSERT(sme != NULL);
-       KASSERT(mutex_owned(&sme->sme_mtx));

       error = workqueue_create(&sme->sme_wq, sme->sme_name,
           sme_events_worker, sme, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE);
@@ -571,7 +570,9 @@ sme_events_init(struct sysmon_envsys *sm
       callout_init(&sme->sme_callout, CALLOUT_MPSAFE);
       callout_setfunc(&sme->sme_callout, sme_events_check, sme);
       sme->sme_callout_state = SME_CALLOUT_READY;
+       mutex_enter(&sme->sme_mtx);
       sme_schedule_callout(sme);
+       mutex_exit(&sme->sme_mtx);
       DPRINTF(("%s: events framework initialized for '%s'\n",
           __func__, sme->sme_name));

@@ -736,14 +737,13 @@ sme_events_check(void *arg)

       KASSERT(sme != NULL);

-       mutex_enter(&sme->sme_work_mtx);
+       mutex_enter(&sme->sme_mtx);
       if (sme->sme_busy > 0) {
               log(LOG_WARNING, "%s: workqueue busy: updates stopped\n",
                   sme->sme_name);
-               mutex_exit(&sme->sme_work_mtx);
+               mutex_exit(&sme->sme_mtx);
               return;
       }
-       mutex_enter(&sme->sme_mtx);
       LIST_FOREACH(see, &sme->sme_events_list, see_list) {
               workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL);
               see->see_edata->flags |= ENVSYS_FNEED_REFRESH;
@@ -752,7 +752,6 @@ sme_events_check(void *arg)
       if (!sysmon_low_power)
               sme_schedule_callout(sme);
       mutex_exit(&sme->sme_mtx);
-       mutex_exit(&sme->sme_work_mtx);
}

/*
@@ -772,7 +771,7 @@ sme_events_worker(struct work *wk, void
       KASSERT(sme != NULL);
       KASSERT(edata != NULL);

-       mutex_enter(&sme->sme_mtx);
+       sysmon_envsys_acquire(sme, false);
       see->see_flags |= SEE_EVENT_WORKING;
       /*
        * sme_events_check marks the sensors to make us refresh them here.
@@ -829,11 +828,10 @@ sme_events_worker(struct work *wk, void

out:
       see->see_flags &= ~SEE_EVENT_WORKING;
-       cv_broadcast(&sme->sme_condvar);
-       mutex_enter(&sme->sme_work_mtx);
+       mutex_enter(&sme->sme_mtx);
       KASSERT(sme->sme_busy > 0);
       sme->sme_busy--;
-       mutex_exit(&sme->sme_work_mtx);
+       sysmon_envsys_release(sme, true);
       mutex_exit(&sme->sme_mtx);
}

@@ -850,7 +848,7 @@ sysmon_envsys_sensor_event(struct sysmon
{
       sme_event_t *see;

-       mutex_enter(&sme->sme_mtx);
+       sysmon_envsys_acquire(sme, false);
       LIST_FOREACH(see, &sme->sme_events_list, see_list) {
               if (edata != see->see_edata)
                       continue;
@@ -861,7 +859,7 @@ sysmon_envsys_sensor_event(struct sysmon
                               break;
               }
       }
-       mutex_exit(&sme->sme_mtx);
+       sysmon_envsys_release(sme, false);
}

/*
Index: sys/dev/sysmon/sysmon_envsysvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/sysmon_envsysvar.h,v
retrieving revision 1.47
diff -p -u -r1.47 sysmon_envsysvar.h
--- sys/dev/sysmon/sysmon_envsysvar.h   23 Nov 2014 10:00:20 -0000      1.47
+++ sys/dev/sysmon/sysmon_envsysvar.h   26 Nov 2018 23:17:24 -0000
@@ -101,10 +101,9 @@ struct sme_descr_entry {
       const char      *desc;
};

-/*
+/*
 * common stuff.
 */
-extern kmutex_t sme_global_mtx;        /* for the sme linked list and dict */
extern prop_dictionary_t sme_propd;    /* the global sensor dictionary */

/*
Index: sys/dev/sysmon/sysmonvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/sysmonvar.h,v
retrieving revision 1.50
diff -p -u -r1.50 sysmonvar.h
--- sys/dev/sysmon/sysmonvar.h  11 Sep 2017 06:02:09 -0000      1.50
+++ sys/dev/sysmon/sysmonvar.h  26 Nov 2018 23:17:24 -0000
@@ -212,11 +212,8 @@ struct sysmon_envsys {
       /*
        * Locking/synchronization.
        */
-       int sme_busy;                   /* number of items on workqueue,
-                                          sme_mtx or sme_work_mtx to read,
-                                          both to write */
+       int sme_busy;                   /* number of items on workqueue */
       kmutex_t sme_mtx;
-       kmutex_t sme_work_mtx;
       kcondvar_t sme_condvar;
};