diff options
Diffstat (limited to 'cpukit/libcsupport/src/privateenv.c')
-rw-r--r-- | cpukit/libcsupport/src/privateenv.c | 204 |
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, ¤t_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(¤t_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; +} |