Example #1
0
int apc_sem_create(int proj, int initval TSRMLS_DC)
{
    int semid;
    int perms = 0777;
    union semun arg;
    key_t key = IPC_PRIVATE;

    if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms)) >= 0) {
        /* sempahore created for the first time, initialize now */
        arg.val = initval;
        if (semctl(semid, 0, SETVAL, arg) < 0) {
            apc_error("apc_sem_create: semctl(%d,...) failed:" TSRMLS_CC, semid);
        }
    }
    else if (errno == EEXIST) {
        /* sempahore already exists, don't initialize */
        if ((semid = semget(key, 1, perms)) < 0) {
            apc_error("apc_sem_create: semget(%u,...) failed:" TSRMLS_CC, key);
        }
        /* insert <sleazy way to avoid race condition> here */
    }
    else {
        apc_error("apc_sem_create: semget(%u,...) failed:" TSRMLS_CC, key);
    }

    return semid;
}
Example #2
0
void apc_shm_detach(apc_segment_t* segment)
{
    if (shmdt(segment->shmaddr) < 0) {
        apc_error("apc_shm_detach: shmdt failed:");
    }

#ifdef APC_MEMPROTECT
    if (segment->roaddr && shmdt(segment->roaddr) < 0) {
        apc_error("apc_shm_detach: shmdt failed:");
    }
#endif
}
Example #3
0
apc_segment_t apc_shm_attach(int shmid, size_t size)
{
    apc_segment_t segment; /* shm segment */

    if ((zend_long)(segment.shmaddr = shmat(shmid, 0, 0)) == -1) {
        apc_error("apc_shm_attach: shmat failed:");
    }

#ifdef APC_MEMPROTECT
    
    if ((zend_long)(segment.roaddr = shmat(shmid, 0, SHM_RDONLY)) == -1) {
        segment.roaddr = NULL;
    }

#endif

    segment.size = size;

    /*
     * We set the shmid for removal immediately after attaching to it. The
     * segment won't disappear until all processes have detached from it.
     */
    apc_shm_destroy(shmid);
    return segment;
}
Example #4
0
/* {{{ apc_cache_preload shall load the prepared data files in path into the specified cache */
PHP_APCU_API zend_bool apc_cache_preload(apc_cache_t* cache, const char *path)
{
#ifndef ZTS	
	zend_bool result = 0;
	char file[MAXPATHLEN]={0,};
	int ndir, i;
	char *p = NULL;
	struct dirent **namelist = NULL;

	if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0) {
		for (i = 0; i < ndir; i++) {
			/* check for extension */
			if (!(p = strrchr(namelist[i]->d_name, '.'))
					|| (p && strcmp(p, ".data"))) {
				free(namelist[i]);
				continue;
			}

			snprintf(file, MAXPATHLEN, "%s%c%s",
					path, DEFAULT_SLASH, namelist[i]->d_name);

			if(apc_load_data(cache, file)) {
				result = 1;
			}
			free(namelist[i]);
		}
		free(namelist);
	}
	return result;
#else 
	apc_error("Cannot load data from apc.preload_path=%s in thread-safe mode", path);
	return 0;
#endif	
} /* }}} */
Example #5
0
void* apc_erealloc(void* p, size_t n TSRMLS_DC)
{
    p = realloc(p, n);
    if (p == NULL) {
        apc_error("apc_erealloc: realloc failed to allocate %u bytes:" TSRMLS_CC, n);
    }
    return p;
}
Example #6
0
void* apc_emalloc(size_t n TSRMLS_DC)
{
    void* p = malloc(n);
    if (p == NULL) {
        apc_error("apc_emalloc: malloc failed to allocate %u bytes:" TSRMLS_CC, n);
    }
    return p;
}
Example #7
0
int apc_sem_get_value(int semid TSRMLS_DC)
{
    union semun arg;
    unsigned short val[1];

    arg.array = val;
    if (semctl(semid, 0, GETALL, arg) < 0) {
        apc_error("apc_sem_getvalue: semctl(%d,...) failed:" TSRMLS_CC, semid);
    }
    return val[0];
}
Example #8
0
/* {{{ apc_cache_create */
PHP_APCU_API apc_cache_t* apc_cache_create(apc_sma_t* sma, apc_serializer_t* serializer, zend_long size_hint, zend_long gc_ttl, zend_long ttl, zend_long smart, zend_bool defend) {
	apc_cache_t* cache;
    zend_long cache_size;
    zend_long nslots;

	/* calculate number of slots */
    nslots = make_prime(size_hint > 0 ? size_hint : 2000);

	/* allocate pointer by normal means */
    cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t));

	/* calculate cache size for shm allocation */
    cache_size = sizeof(apc_cache_header_t) + nslots*sizeof(apc_cache_slot_t*);

	/* allocate shm */
    cache->shmaddr = sma->smalloc(cache_size);

    if(!cache->shmaddr) {
        apc_error("Unable to allocate shared memory for cache structures.  (Perhaps your shared memory size isn't large enough?). ");
        return NULL;
    }
	
	/* zero shm */
    memset(cache->shmaddr, 0, cache_size);

	/* set default header */
    cache->header = (apc_cache_header_t*) cache->shmaddr;
	
    cache->header->nhits = 0;
    cache->header->nmisses = 0;
	cache->header->nentries = 0;
    cache->header->nexpunges = 0;
    cache->header->gc = NULL;
    cache->header->stime = time(NULL);
	cache->header->state |= APC_CACHE_ST_NONE;
	
	/* set cache options */
    cache->slots = (apc_cache_slot_t**) (((char*) cache->shmaddr) + sizeof(apc_cache_header_t));
    cache->sma = sma;
	cache->serializer = serializer;
	cache->nslots = nslots;
    cache->gc_ttl = gc_ttl;
    cache->ttl = ttl;
	cache->smart = smart;
	cache->defend = defend;
	
	/* header lock */
	CREATE_LOCK(&cache->header->lock);

	/* zero slots */
    memset(cache->slots, 0, sizeof(apc_cache_slot_t*)*nslots);

    return cache;
} /* }}} */
Example #9
0
/* {{{ uninstall_class */
static int uninstall_class(apc_class_t cl TSRMLS_DC)
{
    int status;

    status = zend_hash_del(EG(class_table),
                           cl.name,
                           cl.name_len+1);
    if (status == FAILURE) {
        apc_error("Cannot delete class %s" TSRMLS_CC, cl.name);
    }
    return status;
}
Example #10
0
int apc_shm_create(int proj, size_t size)
{
    int shmid;			/* shared memory id */
    int oflag;			/* permissions on shm */
    key_t key = IPC_PRIVATE;	/* shm key */

    oflag = IPC_CREAT | SHM_R | SHM_A;
    if ((shmid = shmget(key, size, oflag)) < 0) {
        apc_error("apc_shm_create: shmget(%d, %d, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment.", key, size, oflag, strerror(errno));
    }

    return shmid;
}
Example #11
0
void apc_sem_wait_for_zero(int semid TSRMLS_DC)
{
    struct sembuf op;

    op.sem_num = 0;
    op.sem_op  = 0;
    op.sem_flg = UNDO;

    if (semop(semid, &op, 1) < 0) {
        if (errno != EINTR) {
            apc_error("apc_sem_waitforzero: semop(%d) failed:" TSRMLS_CC, semid);
        }
    }
}
Example #12
0
void apc_sem_unlock(int semid TSRMLS_DC)
{
    struct sembuf op;

    op.sem_num = 0;
    op.sem_op  = 1;
    op.sem_flg = UNDO;

    if (semop(semid, &op, 1) < 0) {
        if (errno != EINTR) {
            apc_error("apc_sem_unlock: semop(%d) failed:" TSRMLS_CC, semid);
        }
    }
}
Example #13
0
/*
 * s_lock_stuck() - complain about a stuck spinlock
 */
static void
s_lock_stuck(volatile slock_t *lock, const char *file, int line TSRMLS_DC)
{
#if defined(S_LOCK_TEST)
	fprintf(stderr,
			"\nStuck spinlock (%p) detected at %s:%d.\n",
			lock, file, line);
	exit(1);
#else
  /* -- Removed for APC
	elog(PANIC, "stuck spinlock (%p) detected at %s:%d",
		 lock, file, line);
  */
  apc_error("Stuck spinlock (%p) detected" TSRMLS_CC, lock);
#endif
}
Example #14
0
int apc_sem_nonblocking_lock(int semid TSRMLS_DC) 
{
    struct sembuf op;

    op.sem_num = 0;
    op.sem_op  = -1;
    op.sem_flg = UNDO | IPC_NOWAIT;

    if (semop(semid, &op, 1) < 0) {
      if (errno == EAGAIN) {
        return 0;  /* Lock is already held */
      } else if (errno != EINTR) {
        apc_error("apc_sem_lock: semop(%d) failed:" TSRMLS_CC, semid);
      }
    }

    return 1;  /* Lock obtained */
}
Example #15
0
/* {{{ apc_iterator_clone */
static zend_object* apc_iterator_clone(zval *zobject) {
    apc_error(APC_ITERATOR_NAME " object cannot be cloned");
    return NULL;
}
Example #16
0
/* {{{ install_class */
static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC)
{
    zend_class_entry* class_entry = cl.class_entry;
    zend_class_entry* parent = NULL;
    int status;

    /* Special case for mangled names. Mangled names are unique to a file.
     * There is no way two classes with the same mangled name will occur,
     * unless a file is included twice. And if in case, a file is included
     * twice, all mangled name conflicts can be ignored and the class redeclaration
     * error may be deferred till runtime of the corresponding DECLARE_CLASS
     * calls.
     */

    if(cl.name_len != 0 && cl.name[0] == '\0') {
        if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
            return SUCCESS;
        }
    }

    if(lazy && cl.name_len != 0 && cl.name[0] != '\0') {
        status = zend_hash_add(APCG(lazy_class_table),
                               cl.name,
                               cl.name_len+1,
                               &cl,
                               sizeof(apc_class_t),
                               NULL);
        if(status == FAILURE) {
            zend_error(E_ERROR, "Cannot redeclare class %s", cl.name);
        }
        return status;
    }

    class_entry =
        apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC);
    if (class_entry == NULL)
        return FAILURE;


    /* restore parent class pointer for compile-time inheritance */
    if (cl.parent_name != NULL) {
        zend_class_entry** parent_ptr = NULL;
        /*
         * __autoload brings in the old issues with mixed inheritance.
         * When a statically inherited class triggers autoload, it runs
         * afoul of a potential require_once "parent.php" in the previous 
         * line, which when executed provides the parent class, but right
         * now goes and hits __autoload which could fail. 
         * 
         * missing parent == re-compile. 
         *
         * whether __autoload is enabled or not, because __autoload errors
         * cause php to die.
         *
         * Aside: Do NOT pass *strlen(cl.parent_name)+1* because
         * zend_lookup_class_ex does it internally anyway!
         */
        status = zend_lookup_class_ex(cl.parent_name,
                                    strlen(cl.parent_name), 
#ifdef ZEND_ENGINE_2_4
                                    NULL,
#endif
                                    0,
                                    &parent_ptr TSRMLS_CC);
        if (status == FAILURE) {
            if(APCG(report_autofilter)) {
                apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name);
            }
            class_entry->parent = NULL;
            return status;
        }
        else {
            parent = *parent_ptr;
            class_entry->parent = parent;
            zend_do_inheritance(class_entry, parent TSRMLS_CC);
        }
    }

    status = zend_hash_add(EG(class_table),
                           cl.name,
                           cl.name_len+1,
                           &class_entry,
                           sizeof(zend_class_entry*),
                           NULL);

    if (status == FAILURE) {
        apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name);
    }

    return status;
}
Example #17
0
apc_segment_t apc_mmap(char *file_mask, size_t size TSRMLS_DC)
{
    apc_segment_t segment; 

    int fd = -1;
    int flags = MAP_SHARED | MAP_NOSYNC;
#ifdef APC_MEMPROTECT
    int remap = 1;
#endif

    /* If no filename was provided, do an anonymous mmap */
    if(!file_mask || (file_mask && !strlen(file_mask))) {
#if !defined(MAP_ANON)
        apc_error("Anonymous mmap does not apear to be available on this system (MAP_ANON/MAP_ANONYMOUS).  Please see the apc.mmap_file_mask INI option." TSRMLS_CC);
#else
        fd = -1;
        flags = MAP_SHARED | MAP_ANON;
#ifdef APC_MEMPROTECT
        remap = 0;
#endif
#endif
    } else if(!strcmp(file_mask,"/dev/zero")) { 
        fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
        if(fd == -1) {
            apc_error("apc_mmap: open on /dev/zero failed:" TSRMLS_CC);
            goto error;
        }
#ifdef APC_MEMPROTECT
        remap = 0; /* cannot remap */
#endif
    } else if(strstr(file_mask,".shm")) {
        /*
         * If the filemask contains .shm we try to do a POSIX-compliant shared memory
         * backed mmap which should avoid synchs on some platforms.  At least on
         * FreeBSD this implies MAP_NOSYNC and on Linux it is equivalent of mmap'ing
         * a file in a mounted shmfs.  For this to work on Linux you need to make sure
         * you actually have shmfs mounted.  Also on Linux, make sure the file_mask you
         * pass in has a leading / and no other /'s.  eg.  /apc.shm.XXXXXX
         * On FreeBSD these are mapped onto the regular filesystem so you can put whatever
         * path you want here.
         */
        if(!mktemp(file_mask)) {
            apc_error("apc_mmap: mktemp on %s failed:" TSRMLS_CC, file_mask);
            goto error;
        }
        fd = shm_open(file_mask, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
        if(fd == -1) {
            apc_error("apc_mmap: shm_open on %s failed:" TSRMLS_CC, file_mask);
            goto error;
        }
        if (ftruncate(fd, size) < 0) {
            close(fd);
            shm_unlink(file_mask);
            apc_error("apc_mmap: ftruncate failed:" TSRMLS_CC);
            goto error;
        }
        shm_unlink(file_mask);
    } else {
        /*
         * Otherwise we do a normal filesystem mmap
         */
        fd = mkstemp(file_mask);
        if(fd == -1) {
            apc_error("apc_mmap: mkstemp on %s failed:" TSRMLS_CC, file_mask);
            goto error;
        }
        if (ftruncate(fd, size) < 0) {
            close(fd);
            unlink(file_mask);
            apc_error("apc_mmap: ftruncate failed:" TSRMLS_CC);
            goto error;
        }
        unlink(file_mask);
    }

    segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
    segment.size = size;

#ifdef APC_MEMPROTECT
    if(remap) {
        segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0);
    } else {
        segment.roaddr = NULL;
    }
#endif

    if((long)segment.shmaddr == -1) {
        apc_error("apc_mmap: mmap failed:" TSRMLS_CC);
    }

    if(fd != -1) close(fd);
    
    return segment;

error:

    segment.shmaddr = (void*)-1;
    segment.size = 0;
#ifdef APC_MEMPROTECT
    segment.roaddr = NULL;
#endif
    return segment;
}