> > apr_shm_remove()! :)
... not under apr-0 unfortunately, but I've worked around it. :-)
> I'm guessing other processes could still write to the shared memory under
> the SysV model (since the file is just a pointer to a memory address), what
> about under mmap?
Here's what I've come up with. Check out new_shmem_segment() and
apr0_shm_remove() and let me know what you think.
Thanks,
Tyler
/*
* mod_bt - Making Things Better For Seeders
* Copyright 2004, 2005, 2006 Tyler MacDonald <[EMAIL PROTECTED]>
*
* Licensed 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.
*/
/* libc */
#include <stdio.h>
/* APR */
#include <apr.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_file_info.h>
#include <apr_file_io.h>
/* local */
#include <libbtt/types/bt_tracker.h>
#include <libbtt/tracker/tracker.h>
/* Private Functions */
static char* shmem_filename(const char* homedir)
{
static char tmpfile[BT_PATH_LEN];
int len;
if((len = strlen(homedir) + strlen(BT_SHMEM)) > (BT_PATH_LEN - 1))
{
fprintf(stderr, "shmem_filename(): Path \"%s%s\" is too long! (%d>%d chars)\n", homedir, BT_SHMEM, len, BT_PATH_LEN - 1);
fflush(stderr);
return NULL;
}
strcpy(tmpfile, homedir);
strcat(tmpfile, BT_SHMEM);
return tmpfile;
}
static apr_shm_t* join_shmem_segment (apr_pool_t* p, const char* homedir)
{
apr_shm_t *m = NULL;
int ret;
char* shfile = apr_pstrdup(p, shmem_filename(homedir));
if(!shfile)
return NULL;
if((ret = apr_shm_attach(&m, shfile, p)) != APR_SUCCESS)
{
fprintf(stderr, "join_shmem_segment(): Failed to connect to segment in \"%s\": %s\n", shfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
m = NULL;
}
return m;
}
/* stay compatible with apr-0 */
static int apr0_shm_remove (const char *shfile, apr_pool_t *p) {
int ret;
apr_shm_t* shmem = NULL;
if((ret = apr_shm_attach(&shmem, shfile, p)) != APR_SUCCESS) {
return ret;
} else {
if(APR_STATUS_IS_EINVAL(ret)) {
return apr_file_remove(shfile, p);
} else {
return apr_shm_destroy(shmem);
}
}
}
static apr_shm_t* new_shmem_segment (apr_pool_t* p, const char* homedir, size_t size)
{
apr_shm_t* rv = NULL;
apr_file_t* shlock = NULL;
int ret;
char *shfile = apr_pstrdup(p, shmem_filename(homedir));
char *shlockfile = apr_pstrcat(p, shfile, ".lock", NULL);
if(!shfile)
return NULL;
/* TODO: move this into small inline functions for readability */
/* obtain an exclusive lock before attempting to create the tracker. */
if(
(ret = apr_file_open(
&shlock, shlockfile, APR_WRITE | APR_CREATE, APR_OS_DEFAULT, p
)) != APR_SUCCESS
) {
fprintf(stderr, "apr_file_open(%s) for writing failed: %s\n", shlockfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
} else {
if((ret = apr_file_lock(shlock, APR_FLOCK_EXCLUSIVE | APR_FLOCK_NONBLOCK)) != APR_SUCCESS) {
fprintf(stderr, "apr_file_lock(%s) failed: %s", shlockfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
} else {
/* now that we have our lock, attempt to create a segment. */
if((ret = apr_shm_create(&rv, size, shfile, p)) != APR_SUCCESS) {
/* if the segment already exists, try to get rid of it and create it again. */
if(APR_STATUS_IS_EEXIST(ret)) {
if((ret = apr0_shm_remove(shfile, p)) != APR_SUCCESS) {
fprintf(stderr, "apr0_shm_remove(%s) failed: %s", shfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
} else {
if((ret = apr_shm_create(&rv, size, shfile, p)) != APR_SUCCESS) {
fprintf(stderr, "apr_shm_create(&rv, %d, \"%s\", pool) failed: %s\n", size, shfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
}
}
} else {
fprintf(stderr, "apr_shm_create(&rv, %d, \"%s\", pool) failed: %s\n", size, shfile, apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
}
}
}
}
return rv;
}
/* Public Functions */
bt_tracker* bt_tracker_alloc(apr_pool_t* p, const char* homedir, int master)
{
bt_tracker* rv = NULL;
int ret;
if((rv = apr_pcalloc(p, sizeof(bt_tracker))))
{
*rv = new_bt_tracker;
if((ret = apr_pool_create(&(rv->p), p)) == APR_SUCCESS)
{
rv->homedir = apr_pstrdup(p, homedir);
if(master)
{
if((rv->m = new_shmem_segment(rv->p, homedir, sizeof(bt_tracker_config) + sizeof(bt_tracker_stats))) == NULL)
{
/* new_shmem_segment will print an error. */
rv = NULL;
}
}
else
{
if((rv->m = join_shmem_segment(rv->p, homedir)) == NULL)
{
/* join_shmem_segment will print an error. */
rv = NULL;
}
}
}
else
{
fprintf(stderr, "bt_tracker_alloc(): Failed to create a sub-pool for the tracker: %s\n", apr_strerror(ret, bt_error_msg, sizeof(bt_error_msg)));
fflush(stderr);
rv = NULL;
}
}
else
{
fprintf(stderr, "bt_tracker_alloc(): Failed to allocate %d bytes!\n", sizeof(bt_tracker));
fflush(stderr);
rv = NULL;
}
return rv;
}