summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/dso.c
blob: 46af5499ff5196b518f74671b14c63d5df0213b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you under the Apache License, Version 2.0 (the
 *    "License"); you may not use this file except in compliance
 *    with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing,
 *    software distributed under the License is distributed on an
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *    KIND, either express or implied.  See the License for the
 *    specific language governing permissions and limitations
 *    under the License.
 * ====================================================================
 */

#include <apr_thread_mutex.h>
#include <apr_hash.h>

#include "svn_hash.h"
#include "svn_dso.h"
#include "svn_pools.h"
#include "svn_private_config.h"

#include "private/svn_mutex.h"
#include "private/svn_atomic.h"
#include "private/svn_subr_private.h"

/* A mutex to protect our global pool and cache. */
static svn_mutex__t *dso_mutex = NULL;

/* Global pool to allocate DSOs in. */
static apr_pool_t *dso_pool;

/* Global cache for storing DSO objects. */
static apr_hash_t *dso_cache;

/* Just an arbitrary location in memory... */
static int not_there_sentinel;

static volatile svn_atomic_t atomic_init_status = 0;

/* A specific value we store in the dso_cache to indicate that the
   library wasn't found.  This keeps us from allocating extra memory
   from dso_pool when trying to find libraries we already know aren't
   there.  */
#define NOT_THERE ((void *) &not_there_sentinel)

static svn_error_t *
atomic_init_func(void *baton,
                 apr_pool_t *pool)
{
  dso_pool = svn_pool_create(NULL);

  SVN_ERR(svn_mutex__init(&dso_mutex, TRUE, dso_pool));

  dso_cache = apr_hash_make(dso_pool);
  return SVN_NO_ERROR;
}

svn_error_t *
svn_dso_initialize2(void)
{
  SVN_ERR(svn_atomic__init_once(&atomic_init_status, atomic_init_func,
                                NULL, NULL));

  return SVN_NO_ERROR;
}

#if APR_HAS_DSO
static svn_error_t *
svn_dso_load_internal(apr_dso_handle_t **dso, const char *fname)
{
  *dso = svn_hash_gets(dso_cache, fname);

  /* First check to see if we've been through this before...  We do this
     to avoid calling apr_dso_load multiple times for a given library,
     which would result in wasting small amounts of memory each time. */
  if (*dso == NOT_THERE)
    {
      *dso = NULL;
      return SVN_NO_ERROR;
    }

  /* If we got nothing back from the cache, try and load the library. */
  if (! *dso)
    {
      apr_status_t status = apr_dso_load(dso, fname, dso_pool);
      if (status)
        {
#ifdef SVN_DEBUG_DSO
          char buf[1024];
          fprintf(stderr,
                  "Dynamic loading of '%s' failed with the following error:\n%s\n",
                  fname,
                  apr_dso_error(*dso, buf, 1024));
#endif
          *dso = NULL;

          /* It wasn't found, so set the special "we didn't find it" value. */
          svn_hash_sets(dso_cache, apr_pstrdup(dso_pool, fname), NOT_THERE);

          return SVN_NO_ERROR;
        }

      /* Stash the dso so we can use it next time. */
      svn_hash_sets(dso_cache, apr_pstrdup(dso_pool, fname), *dso);
    }

  return SVN_NO_ERROR;
}

svn_error_t *
svn_dso_load(apr_dso_handle_t **dso, const char *fname)
{
  SVN_ERR(svn_dso_initialize2());

  SVN_MUTEX__WITH_LOCK(dso_mutex, svn_dso_load_internal(dso, fname));

  return SVN_NO_ERROR;
}

apr_pool_t *
svn_dso__pool(void)
{
  return dso_pool;
}

#endif /* APR_HAS_DSO */