blob: 750110c533d66aea9581202f8ed7b374cff77f3f [file] [log] [blame]
/* 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 "mod_perl.h"
void modperl_global_request_cfg_set(request_rec *r)
{
MP_dDCFG;
MP_dRCFG;
/* only if PerlOptions +GlobalRequest and not done already */
if (MpDirGLOBAL_REQUEST(dcfg) && !MpReqSET_GLOBAL_REQUEST(rcfg)) {
modperl_global_request_set(r);
}
}
void modperl_global_request_set(request_rec *r)
{
MP_dRCFG;
request_rec *old_r = NULL;
/* reset old value, important for subrequests */
(void)modperl_tls_get_request_rec(&old_r);
modperl_tls_reset_cleanup_request_rec(r->pool, old_r);
modperl_tls_set_request_rec(r);
/* so 'PerlOptions +GlobalRequest' doesnt wipe us out */
MpReqSET_GLOBAL_REQUEST_On(rcfg);
}
/* get/set */
request_rec *modperl_global_request(pTHX_ SV *svr)
{
request_rec *cur = NULL;
apr_status_t status = modperl_tls_get_request_rec(&cur);
if (status != APR_SUCCESS) {
/* an internal problem */
Perl_croak(aTHX_ "failed to retrieve the request object");
}
if (GIMME_V != G_VOID && !cur) {
/* wrong configuration */
Perl_croak(aTHX_ "Global $r object is not available. Set:\n"
"\tPerlOptions +GlobalRequest\nin httpd.conf");
}
if (svr) {
modperl_global_request_obj_set(aTHX_ svr);
}
return cur;
}
void modperl_global_request_obj_set(pTHX_ SV *svr)
{
/* XXX: support sublassing */
request_rec *r = modperl_sv2request_rec(aTHX_ svr);
modperl_global_request_set(r);
}
#if MP_THREADED
static apr_status_t modperl_global_cleanup(void *data)
{
modperl_global_t *global = (modperl_global_t *)data;
MP_TRACE_g(MP_FUNC, "destroy lock for %s", global->name);
MUTEX_DESTROY(&global->glock);
return APR_SUCCESS;
}
#endif
void modperl_global_init(modperl_global_t *global, apr_pool_t *p,
void *data, const char *name)
{
Zero(global, 1, modperl_global_t);
global->data = data;
global->name = name;
#if MP_THREADED
MUTEX_INIT(&global->glock);
apr_pool_cleanup_register(p, (void *)global,
modperl_global_cleanup,
apr_pool_cleanup_null);
#endif
MP_TRACE_g(MP_FUNC, "init %s", name);
}
void modperl_global_lock(modperl_global_t *global)
{
#if MP_THREADED
MP_TRACE_g(MP_FUNC, "locking %s", global->name);
MUTEX_LOCK(&global->glock);
#endif
}
void modperl_global_unlock(modperl_global_t *global)
{
#if MP_THREADED
MP_TRACE_g(MP_FUNC, "unlocking %s", global->name);
MUTEX_UNLOCK(&global->glock);
#endif
}
void *modperl_global_get(modperl_global_t *global)
{
return global->data;
}
void modperl_global_set(modperl_global_t *global, void *data)
{
global->data = data;
}
/* hopefully there wont be many of these */
#define MP_GLOBAL_IMPL(gname, type) \
\
static modperl_global_t MP_global_##gname; \
\
void modperl_global_init_##gname(apr_pool_t *p, \
type gname) \
{ \
modperl_global_init(&MP_global_##gname, p, \
(void *)gname, #gname); \
} \
\
void modperl_global_lock_##gname(void) \
{ \
modperl_global_lock(&MP_global_##gname); \
} \
\
void modperl_global_unlock_##gname(void) \
{ \
modperl_global_unlock(&MP_global_##gname); \
} \
\
type modperl_global_get_##gname(void) \
{ \
return (type ) \
modperl_global_get(&MP_global_##gname); \
} \
\
void modperl_global_set_##gname(void *data) \
{ \
modperl_global_set(&MP_global_##gname, data); \
} \
MP_GLOBAL_IMPL(pconf, apr_pool_t *)
MP_GLOBAL_IMPL(server_rec, server_rec *)
/*** anon handlers code ***/
static modperl_global_t MP_global_anon_cnt;
void modperl_global_anon_cnt_init(apr_pool_t *p)
{
int *data = (int *)apr_pcalloc(p, sizeof(int));
*data = 0;
modperl_global_init(&MP_global_anon_cnt, p, (void *)data, "anon_cnt");
}
int modperl_global_anon_cnt_next(void)
{
int next;
/* XXX: inline lock/unlock? */
modperl_global_lock(&MP_global_anon_cnt);
next = ++*(int *)(MP_global_anon_cnt.data);
modperl_global_unlock(&MP_global_anon_cnt);
return next;
}
/*** TLS ***/
#if MP_THREADED
static apr_status_t modperl_tls_cleanup(void *data)
{
return apr_threadkey_private_delete((apr_threadkey_t *)data);
}
#endif
apr_status_t modperl_tls_create(apr_pool_t *p, modperl_tls_t **key)
{
#if MP_THREADED
apr_status_t status = apr_threadkey_private_create(key, NULL, p);
apr_pool_cleanup_register(p, (void *)*key,
modperl_tls_cleanup,
apr_pool_cleanup_null);
return status;
#else
*key = apr_pcalloc(p, sizeof(**key));
return APR_SUCCESS;
#endif
}
apr_status_t modperl_tls_get(modperl_tls_t *key, void **data)
{
#if MP_THREADED
if (!key) {
*data = NULL;
return APR_SUCCESS;
}
return apr_threadkey_private_get(data, key);
#else
*data = modperl_global_get((modperl_global_t *)key);
return APR_SUCCESS;
#endif
}
apr_status_t modperl_tls_set(modperl_tls_t *key, void *data)
{
#if MP_THREADED
return apr_threadkey_private_set(data, key);
#else
modperl_global_set((modperl_global_t *)key, data);
return APR_SUCCESS;
#endif
}
typedef struct {
modperl_tls_t *key;
void *data;
} modperl_tls_cleanup_data_t;
static apr_status_t modperl_tls_reset(void *data)
{
modperl_tls_cleanup_data_t *cdata =
(modperl_tls_cleanup_data_t *)data;
return modperl_tls_set(cdata->key, cdata->data);
}
void modperl_tls_reset_cleanup(apr_pool_t *p, modperl_tls_t *key,
void *data)
{
modperl_tls_cleanup_data_t *cdata =
(modperl_tls_cleanup_data_t *)apr_palloc(p, sizeof(*cdata));
cdata->key = key;
cdata->data = data;
apr_pool_cleanup_register(p, (void *)cdata,
modperl_tls_reset,
apr_pool_cleanup_null);
}
/* hopefully there wont be many of these either */
#define MP_TLS_IMPL(gname, type) \
\
static modperl_tls_t *MP_tls_##gname; \
\
apr_status_t \
modperl_tls_create_##gname(apr_pool_t *p) \
{ \
return modperl_tls_create(p, &MP_tls_##gname); \
} \
\
apr_status_t modperl_tls_get_##gname(type *data) \
{ \
void *ptr; \
apr_status_t status = \
modperl_tls_get(MP_tls_##gname, &ptr); \
*data = (type )ptr; \
return status; \
} \
\
apr_status_t modperl_tls_set_##gname(void *data) \
{ \
return modperl_tls_set(MP_tls_##gname, data); \
} \
\
void modperl_tls_reset_cleanup_##gname(apr_pool_t *p, \
type data) \
{ \
modperl_tls_reset_cleanup(p, MP_tls_##gname, \
(void *)data); \
}
MP_TLS_IMPL(request_rec, request_rec *)
/*
* Local Variables:
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/