> > 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;
}

Reply via email to