Module: xenomai-2.6
Branch: master
Commit: cd1c762280126f78c9e8fa3e4118a912dd0e0563
URL:    
http://git.xenomai.org/?p=xenomai-2.6.git;a=commit;h=cd1c762280126f78c9e8fa3e4118a912dd0e0563

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Thu Jun 16 15:11:29 2016 +0200

posix: fix pthread_once

The pthread_once implementation was broken, fix it. It becomes
restricted to Xenomai threads, but this functionality makes no sense for
modules init functions, as a module init function is guaranteed to be
executed once by definition.

---

 ksrc/skins/posix/module.c |   43 +++++++++++++------
 ksrc/skins/posix/once.c   |  104 +++++++++++++++++++++++++++++++++++++++------
 ksrc/skins/posix/once.h   |    8 ++++
 3 files changed, 130 insertions(+), 25 deletions(-)

diff --git a/ksrc/skins/posix/module.c b/ksrc/skins/posix/module.c
index eea6e13..b0c40a2 100644
--- a/ksrc/skins/posix/module.c
+++ b/ksrc/skins/posix/module.c
@@ -63,6 +63,7 @@
 #include <posix/timer.h>
 #include <posix/registry.h>
 #include <posix/shm.h>
+#include <posix/once.h>
 
 MODULE_DESCRIPTION("POSIX/PSE51 interface");
 MODULE_AUTHOR("gilles.chanteperd...@xenomai.org");
@@ -86,6 +87,7 @@ static void pse51_shutdown(int xtype)
 #endif /* CONFIG_XENO_OPT_POSIX_SHM */
        pse51_timer_pkg_cleanup();
        pse51_mq_pkg_cleanup();
+       pse51_once_pkg_cleanup();
        pse51_cond_pkg_cleanup();
        pse51_tsd_pkg_cleanup();
        pse51_sem_pkg_cleanup();
@@ -129,19 +131,9 @@ int SKIN_INIT(posix)
 
 #ifdef CONFIG_XENO_OPT_PERVASIVE
        err = pse51_syscall_init();
+       if (err != 0)
+               goto fail_apc_cleanup;
 #endif /* CONFIG_XENO_OPT_PERVASIVE */
-       if (err != 0) {
-#ifdef __KERNEL__
-               pse51_apc_pkg_cleanup();
-         fail_free_tbase:
-#endif /* __KERNEL__ */
-               xntbase_free(pse51_tbase);
-       fail_shutdown_pod:
-               xnpod_shutdown(err);
-         fail:
-               xnlogerr("POSIX skin init failed, code %d.\n", err);
-               return err;
-       }
 
        pse51_reg_pkg_init(CONFIG_XENO_OPT_POSIX_REGISTRY_NRSLOTS, 
                        CONFIG_XENO_OPT_POSIX_REGISTRY_NRDESCS);
@@ -150,6 +142,11 @@ int SKIN_INIT(posix)
        pse51_sem_pkg_init();
        pse51_tsd_pkg_init();
        pse51_cond_pkg_init();
+
+       err = pse51_once_pkg_init();
+       if (err)
+               goto fail_cond_cleanup;
+
        pse51_mq_pkg_init();
 #ifdef CONFIG_XENO_OPT_POSIX_INTR
        pse51_intr_pkg_init();
@@ -162,6 +159,28 @@ int SKIN_INIT(posix)
        pse51_thread_pkg_init(module_param_value(time_slice_arg));
 
        return 0;
+
+  fail_cond_cleanup:
+       pse51_cond_pkg_cleanup();
+       pse51_tsd_pkg_cleanup();
+       pse51_sem_pkg_cleanup();
+       pse51_mutex_pkg_cleanup();
+       pse51_signal_pkg_cleanup();
+       pse51_reg_pkg_cleanup();
+#ifdef CONFIG_XENO_OPT_PERVASIVE
+       pse51_syscall_cleanup();
+  fail_apc_cleanup:
+#endif /* CONFIG_XENO_OPT_PERVASIVE */
+#ifdef __KERNEL__
+       pse51_apc_pkg_cleanup();
+  fail_free_tbase:
+#endif /* __KERNEL__ */
+       xntbase_free(pse51_tbase);
+  fail_shutdown_pod:
+       xnpod_shutdown(err);
+  fail:
+       xnlogerr("POSIX skin init failed, code %d.\n", err);
+       return err;
 }
 
 void SKIN_EXIT(posix)
diff --git a/ksrc/skins/posix/once.c b/ksrc/skins/posix/once.c
index 8787c1f..ca8c2dd 100644
--- a/ksrc/skins/posix/once.c
+++ b/ksrc/skins/posix/once.c
@@ -23,6 +23,9 @@
 
 #include <posix/internal.h>
 
+static pthread_mutex_t mutex;
+static pthread_cond_t cond;
+
 /**
  * Execute an initialization routine.
  *
@@ -35,34 +38,109 @@
  * @return 0 on success;
  * @return an error number if:
  * - EINVAL, the object pointed to by @a once is invalid (it must have been
- *   initialized with PTHREAD_ONCE_INIT).
+ *   initialized with PTHREAD_ONCE_INIT);
+ * - EPERM, the caller context is invalid.
+ *
+ * @par Valid contexts:
+ * - Xenomai kernel-space thread.
  *
  * @see
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_once.html";>
  * Specification.</a>
  *
  */
-int pthread_once(pthread_once_t * once, void (*init_routine) (void))
+
+static void once_cleanup(void *cookie)
+{
+       pthread_once_t *once = cookie;
+
+       pthread_mutex_lock(&mutex);
+       once->routine_called = 0;
+       pthread_cond_broadcast(&cond);
+       pthread_mutex_unlock(&mutex);
+}
+
+int pthread_once(pthread_once_t *once, void (*init_routine)(void))
 {
-       spl_t s;
+       int err;
 
-       xnlock_get_irqsave(&nklock, s);
+       err = pthread_mutex_lock(&mutex);
+       if (err)
+               return err;
 
        if (!pse51_obj_active(once, PSE51_ONCE_MAGIC, pthread_once_t)) {
-               xnlock_put_irqrestore(&nklock, s);
-               return EINVAL;
+               err = EINVAL;
+               goto out;
        }
 
-       if (!once->routine_called) {
-               init_routine();
-               /* If the calling thread is canceled while executing 
init_routine,
-                  routine_called will not be set to 1. */
-               once->routine_called = 1;
+       while (once->routine_called != 2)
+               switch (once->routine_called) {
+               case 0:
+                       once->routine_called = 1;
+                       pthread_mutex_unlock(&mutex);
+
+                       pthread_cleanup_push(once_cleanup, once);
+                       init_routine();
+                       pthread_cleanup_pop(0);
+
+                       pthread_mutex_lock(&mutex);
+                       once->routine_called = 2;
+                       pthread_cond_broadcast(&cond);
+                       break;
+
+               case 1:
+                       err = pthread_cond_wait(&cond, &mutex);
+                       if (err)
+                               goto out;
+                       break;
+
+               default:
+                       err = EINVAL;
+                       goto out;
+               }
+
+  out:
+       pthread_mutex_unlock(&mutex);
+
+       return err;
+}
+
+int pse51_once_pkg_init(void)
+{
+       pthread_mutexattr_t tattr;
+       int err;
+
+       err = pthread_mutexattr_init(&tattr);
+       if (err) {
+               printk("Posix: pthread_once/pthread_mutexattr_init: %d\n", err);
+               return err;
+       }
+
+       err = pthread_mutexattr_setprotocol(&tattr, PTHREAD_PRIO_INHERIT);
+       if (err) {
+               printk("Posix: pthread_once/set_protocol: %d\n", err);
+               return err;
        }
 
-       xnlock_put_irqrestore(&nklock, s);
+       err = pthread_mutex_init(&mutex, &tattr);
+       if (err) {
+               printk("Posix: pthread_once/mutex_init: %d\n", err);
+               return err;
+       }
+
+       err = pthread_cond_init(&cond, NULL);
+       if (err) {
+               printk("Posix: pthread_once/cond_init: %d\n", err);
+               pthread_mutex_destroy(&mutex);
+       }
 
-       return 0;
+       return err;
+}
+
+void pse51_once_pkg_cleanup(void)
+{
+       pthread_mutex_destroy(&mutex);
+       pthread_cond_destroy(&cond);
 }
 
 /*@}*/
diff --git a/ksrc/skins/posix/once.h b/ksrc/skins/posix/once.h
new file mode 100644
index 0000000..4019b4d
--- /dev/null
+++ b/ksrc/skins/posix/once.h
@@ -0,0 +1,8 @@
+#ifndef _POSIX_ONCE_H
+#define _POSIX_ONCE_H
+
+int pse51_once_pkg_init(void);
+
+void pse51_once_pkg_cleanup(void);
+
+#endif /* _POSIX_ONCE_H */


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to