summaryrefslogtreecommitdiffstats
path: root/cpukit/libcsupport/src/privateenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libcsupport/src/privateenv.c')
-rw-r--r--cpukit/libcsupport/src/privateenv.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c
new file mode 100644
index 0000000000..89137200b7
--- /dev/null
+++ b/cpukit/libcsupport/src/privateenv.c
@@ -0,0 +1,204 @@
+/*
+ * Instantiate a private user environment for the calling thread.
+ *
+ * Submitted by: fernando.ruiz@ctv.es (correo@fernando-ruiz.com)
+ *
+ * COPYRIGHT (c) 1989-2010.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h> /* free */
+
+#include <rtems.h>
+#include <rtems/chain.h>
+#include <rtems/libio_.h>
+
+/* cleanup a user environment
+ * NOTE: this must be called with
+ * thread dispatching disabled!
+ */
+static void
+free_user_env(void *venv)
+{
+ rtems_user_env_t *env = (rtems_user_env_t*) venv ;
+
+ if (env != &rtems_global_user_env
+ #ifdef HAVE_USERENV_REFCNT
+ && --env->refcnt <= 0
+ #endif
+ ) {
+ rtems_filesystem_freenode( &env->current_directory);
+ rtems_filesystem_freenode( &env->root_directory);
+ free(env);
+ }
+}
+
+rtems_status_code rtems_libio_set_private_env(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_id task_id = rtems_task_self();
+ rtems_filesystem_location_info_t root_loc;
+ rtems_filesystem_location_info_t current_loc;
+ rtems_user_env_t *new_env = NULL;
+ int rv = 0;
+
+ rv = rtems_filesystem_evaluate_path("/", 1, 0, &root_loc, 0);
+ if (rv != 0)
+ goto error_0;
+
+ rv = rtems_filesystem_evaluate_path("/", 1, 0, &current_loc, 0);
+ if (rv != 0)
+ goto error_1;
+
+ /*
+ * Malloc is necessary whenever the current task does not
+ * have its own environment in place. This could be:
+ * a) it never had one
+ * OR
+ * b) it shared another task's environment
+ */
+
+ /*
+ * Bharath: I'm not sure if the check can be reduced to
+ * if( rtems_current_user_env->task_id != task_id ) {
+ */
+
+ if (
+ rtems_current_user_env == &rtems_global_user_env
+ || rtems_current_user_env->task_id != task_id
+ ) {
+ new_env = malloc(sizeof(rtems_user_env_t));
+ if (new_env == NULL)
+ goto error_2;
+
+ #ifdef HAVE_USERENV_REFCNT
+ new_env->refcnt = 1;
+ #endif
+
+ sc = rtems_task_variable_add(
+ RTEMS_SELF,
+ (void*)&rtems_current_user_env,
+ (void(*)(void *))free_user_env
+ );
+ if (sc != RTEMS_SUCCESSFUL)
+ goto error_3;
+
+ rtems_current_user_env = new_env;
+ }
+
+ /* Inherit the global values */
+ *rtems_current_user_env = rtems_global_user_env;
+
+ rtems_current_user_env->task_id = task_id;
+
+ /*
+ * Clone the pathlocs. In contrast to most other code we must _not_ free the
+ * original locs because what we are trying to do here is forking off clones.
+ * The reason is a pathloc can be allocated by the file system and needs to
+ * be freed when deleting the environment.
+ */
+ rtems_filesystem_root = root_loc;
+ rtems_filesystem_current = current_loc;
+
+ return RTEMS_SUCCESSFUL;
+
+error_3:
+ free(new_env);
+
+error_2:
+ rtems_filesystem_freenode(&current_loc);
+
+error_1:
+ rtems_filesystem_freenode(&root_loc);
+
+error_0:
+ return RTEMS_NO_MEMORY;
+}
+
+/*
+ * Share the same private environment between two tasks:
+ * Task_id (remote) and RTEMS_SELF(current).
+ */
+
+/* NOTE:
+ *
+ * THIS CODE HAS NO PROTECTION IMPLEMENTED
+ *
+ * Tasks who wish to share their environments must
+ *
+ * a) assert that no participants are concurrently
+ * executing
+ * libio_share_private_env() and/or libio_set_private_env()
+ *
+ * b) mutex access to rtems_filesystem_current, rtems_filesytem_root
+ * while changing any of those (chdir(), chroot()).
+ */
+
+rtems_status_code rtems_libio_share_private_env(rtems_id task_id)
+{
+ rtems_status_code sc;
+ rtems_user_env_t * shared_user_env;
+ rtems_id current_task_id;
+
+ /*
+ * get current task id
+ */
+ current_task_id = rtems_task_self();
+
+ /*
+ * If this was an attempt to share the task with self,
+ * if somebody wanted to do it... Lets tell them, its shared
+ */
+
+ if( task_id == current_task_id )
+ return RTEMS_SUCCESSFUL;
+ /*
+ * Try to get the requested user environment
+ */
+ sc = rtems_task_variable_get(
+ task_id,
+ (void*)&rtems_current_user_env,
+ (void*)&shared_user_env );
+
+ /*
+ * If it was not successful, return the error code
+ */
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ /*
+ * If we are here, we have the required environment to be
+ * shared with the current task
+ */
+
+ /*
+ * If we have a current environment in place, we need to
+ * free it, since we will be sharing the variable with the
+ * shared_user_env
+ */
+
+ if (rtems_current_user_env->task_id==current_task_id) {
+ rtems_user_env_t *tmp = rtems_current_user_env;
+ free_user_env( tmp );
+ }
+
+ /* the current_user_env is the same pointer that remote env */
+ rtems_current_user_env = shared_user_env;
+
+ /* increase the reference count */
+#ifdef HAVE_USERENV_REFCNT
+ rtems_current_user_env->refcnt++;
+#endif
+
+ return RTEMS_SUCCESSFUL;
+}