source: rtems/cpukit/libcsupport/src/privateenv.c @ 1becaa9

5
Last change on this file since 1becaa9 was 66fac03, checked in by Sebastian Huber <sebastian.huber@…>, on 03/16/17 at 10:54:29

libio: Fix deadlock in location management

Perform a context-dependent deferred location release to avoid a
deadlock on the file system instance locks, for example during a
chdir().

Update #2936.

  • Property mode set to 100644
File size: 2.9 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Instantiate a Private User Environment
5 *  @ingroup LibIOEnv
6 */
7
8/*
9 *  Submitted by: fernando.ruiz@ctv.es (correo@fernando-ruiz.com)
10 *
11 *  COPYRIGHT (c) 1989-2010.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20  #include "config.h"
21#endif
22
23#include <stdlib.h>
24
25#include <rtems/libio_.h>
26#include <rtems/score/threadimpl.h>
27
28/**
29 *  Instantiate a private user environment for the calling thread.
30 */
31
32rtems_user_env_t * rtems_current_user_env_get(void)
33{
34  void *ptr = pthread_getspecific(rtems_current_user_env_key);
35  if (ptr == NULL) {
36    ptr = &rtems_global_user_env;
37  }
38  return (rtems_user_env_t *) ptr;
39}
40
41void rtems_libio_free_user_env(void *arg)
42{
43  rtems_user_env_t *env = arg;
44  bool uses_global_env = env == &rtems_global_user_env;
45
46  if (!uses_global_env) {
47    rtems_filesystem_global_location_release(env->current_directory, false);
48    rtems_filesystem_global_location_release(env->root_directory, false);
49    free(env);
50  }
51}
52
53rtems_status_code rtems_libio_set_private_env(void)
54{
55  rtems_status_code sc = RTEMS_SUCCESSFUL;
56  rtems_user_env_t *old_env = rtems_current_user_env;
57  bool uses_global_env = old_env == &rtems_global_user_env;
58
59  if (uses_global_env) {
60    Thread_Life_state life_state =
61      _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
62    rtems_user_env_t *new_env = calloc(1, sizeof(*new_env));
63
64    if (new_env != NULL) {
65      *new_env = *old_env;
66      new_env->root_directory =
67        rtems_filesystem_global_location_obtain(&old_env->root_directory);
68      new_env->current_directory =
69        rtems_filesystem_global_location_obtain(&old_env->current_directory);
70
71      if (
72        !rtems_filesystem_global_location_is_null(new_env->root_directory)
73          && !rtems_filesystem_global_location_is_null(new_env->current_directory)
74      ) {
75        int eno = pthread_setspecific(
76          rtems_current_user_env_key,
77          new_env
78        );
79
80        if (eno == 0) {
81          rtems_libio_free_user_env(old_env);
82        } else {
83          sc = RTEMS_TOO_MANY;
84        }
85      } else {
86        sc = RTEMS_UNSATISFIED;
87      }
88
89      if (sc != RTEMS_SUCCESSFUL) {
90        rtems_libio_free_user_env(new_env);
91      }
92    } else {
93      sc = RTEMS_NO_MEMORY;
94    }
95
96    _Thread_Set_life_protection(life_state);
97  }
98
99  return sc;
100}
101
102void rtems_libio_use_global_env(void)
103{
104  rtems_user_env_t *env = rtems_current_user_env;
105  bool uses_private_env = env != &rtems_global_user_env;
106
107  if (uses_private_env) {
108    Thread_Life_state life_state =
109      _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
110
111    rtems_libio_free_user_env(env);
112    pthread_setspecific(rtems_current_user_env_key, NULL);
113
114    _Thread_Set_life_protection(life_state);
115  }
116}
Note: See TracBrowser for help on using the repository browser.