Ejemplo n.º 1
0
/*
 * pj_thread_create(...)
 */
pj_status_t pj_thread_create( pj_pool_t *pool,
				      const char *thread_name,
				      pj_thread_proc *proc,
				      void *arg,
				      pj_size_t stack_size,
				      unsigned flags,
				      pj_thread_t **ptr_thread)
{
#if PJ_HAS_THREADS
    pj_thread_t *rec;
    pthread_attr_t thread_attr;
    void *stack_addr;
    int rc;

    PJ_UNUSED_ARG(stack_addr);

    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);

    /* Create thread record and assign name for the thread */
    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
    PJ_ASSERT_RETURN(rec, PJ_ENOMEM);

    /* Set name. */
    if (!thread_name)
	thread_name = "thr%p";

    if (strchr(thread_name, '%')) {
	pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
    } else {
	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
    }

    /* Set default stack size */
    if (stack_size == 0)
	stack_size = PJ_THREAD_DEFAULT_STACK_SIZE;

#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
    rec->stk_size = stack_size;
    rec->stk_max_usage = 0;
#endif

    /* Emulate suspended thread with mutex. */
    if (flags & PJ_THREAD_SUSPENDED) {
	rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
	if (rc != PJ_SUCCESS) {
	    return rc;
	}

	pj_mutex_lock(rec->suspended_mutex);
    } else {
	pj_assert(rec->suspended_mutex == NULL);
    }


    /* Init thread attributes */
    pthread_attr_init(&thread_attr);

#if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0
    /* Set thread's stack size */
    rc = pthread_attr_setstacksize(&thread_attr, stack_size);
    if (rc != 0)
	return PJ_RETURN_OS_ERROR(rc);
#endif	/* PJ_THREAD_SET_STACK_SIZE */


#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0
    /* Allocate memory for the stack */
    stack_addr = pj_pool_alloc(pool, stack_size);
    PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM);

    rc = pthread_attr_setstackaddr(&thread_attr, stack_addr);
    if (rc != 0)
	return PJ_RETURN_OS_ERROR(rc);
#endif	/* PJ_THREAD_ALLOCATE_STACK */


    /* Create the thread. */
    rec->proc = proc;
    rec->arg = arg;
    rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec);
    if (rc != 0) {
	return PJ_RETURN_OS_ERROR(rc);
    }

    *ptr_thread = rec;

    PJ_LOG(6, (rec->obj_name, "Thread created"));
    return PJ_SUCCESS;
#else
    pj_assert(!"Threading is disabled!");
    return PJ_EINVALIDOP;
#endif
}
Ejemplo n.º 2
0
static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )
{
    pj_rbtree_node *temp;

    PJ_CHECK_STACK();

    while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {
        if (node->parent->left == node) {
	    temp = node->parent->right;
	    if (temp->color == PJ_RBCOLOR_RED) {
	        temp->color = PJ_RBCOLOR_BLACK;
	        node->parent->color = PJ_RBCOLOR_RED;
	        left_rotate(tree, node->parent);
	        temp = node->parent->right;
	    }
	    if (temp->left->color == PJ_RBCOLOR_BLACK && 
	        temp->right->color == PJ_RBCOLOR_BLACK) 
	    {
	        temp->color = PJ_RBCOLOR_RED;
	        node = node->parent;
	    } else {
	        if (temp->right->color == PJ_RBCOLOR_BLACK) {
		    temp->left->color = PJ_RBCOLOR_BLACK;
		    temp->color = PJ_RBCOLOR_RED;
		    right_rotate( tree, temp);
		    temp = node->parent->right;
	        }
	        temp->color = node->parent->color;
	        temp->right->color = PJ_RBCOLOR_BLACK;
	        node->parent->color = PJ_RBCOLOR_BLACK;
	        left_rotate(tree, node->parent);
	        node = tree->root;
	    }
        } else {
	    temp = node->parent->left;
	    if (temp->color == PJ_RBCOLOR_RED) {
	        temp->color = PJ_RBCOLOR_BLACK;
	        node->parent->color = PJ_RBCOLOR_RED;
	        right_rotate( tree, node->parent);
	        temp = node->parent->left;
	    }
	    if (temp->right->color == PJ_RBCOLOR_BLACK && 
		temp->left->color == PJ_RBCOLOR_BLACK) 
	    {
	        temp->color = PJ_RBCOLOR_RED;
	        node = node->parent;
	    } else {
	        if (temp->left->color == PJ_RBCOLOR_BLACK) {
		    temp->right->color = PJ_RBCOLOR_BLACK;
		    temp->color = PJ_RBCOLOR_RED;
		    left_rotate( tree, temp);
		    temp = node->parent->left;
	        }
	        temp->color = node->parent->color;
	        node->parent->color = PJ_RBCOLOR_BLACK;
	        temp->left->color = PJ_RBCOLOR_BLACK;
	        right_rotate(tree, node->parent);
	        node = tree->root;
	    }
        }
    }
	
    node->color = PJ_RBCOLOR_BLACK;
}
Ejemplo n.º 3
0
/*
 * pj_sem_create()
 */
pj_status_t pj_sem_create( pj_pool_t *pool,
				   const char *name,
				   unsigned initial,
				   unsigned max,
				   pj_sem_t **ptr_sem)
{
#if PJ_HAS_THREADS
    pj_sem_t *sem;

    PJ_CHECK_STACK();
    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);

    sem = PJ_POOL_ALLOC_T(pool, pj_sem_t);
    PJ_ASSERT_RETURN(sem, PJ_ENOMEM);

#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
    /* MacOS X doesn't support anonymous semaphore */
    {
	char sem_name[PJ_GUID_MAX_LENGTH+1];
	pj_str_t nam;

	/* We should use SEM_NAME_LEN, but this doesn't seem to be
	 * declared anywhere? The value here is just from trial and error
	 * to get the longest name supported.
	 */
#	define MAX_SEM_NAME_LEN	23

	/* Create a unique name for the semaphore. */
	if (PJ_GUID_STRING_LENGTH <= MAX_SEM_NAME_LEN) {
	    nam.ptr = sem_name;
	    pj_generate_unique_string(&nam);
	    sem_name[nam.slen] = '\0';
	} else {
	    pj_create_random_string(sem_name, MAX_SEM_NAME_LEN);
	    sem_name[MAX_SEM_NAME_LEN] = '\0';
	}

	/* Create semaphore */
	sem->sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR,
			    initial);
	if (sem->sem == SEM_FAILED)
	    return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

	/* And immediately release the name as we don't need it */
	sem_unlink(sem_name);
    }
#else
    sem->sem = PJ_POOL_ALLOC_T(pool, sem_t);
    if (sem_init( sem->sem, 0, initial) != 0)
	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
#endif

    /* Set name. */
    if (!name) {
	name = "sem%p";
    }
    if (strchr(name, '%')) {
	pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
    } else {
	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
    }

    PJ_LOG(6, (sem->obj_name, "Semaphore created"));

    *ptr_sem = sem;
    return PJ_SUCCESS;
#else
    *ptr_sem = (pj_sem_t*)1;
    return PJ_SUCCESS;
#endif
}
Ejemplo n.º 4
0
/*
 * pj_getpid(void)
 */
pj_uint32_t pj_getpid(void)
{
    PJ_CHECK_STACK();
    return getpid();
}
Ejemplo n.º 5
0
/*
* pj_ioqueue_sendto()
*
* Start asynchronous write() to the descriptor.
*/
PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
																			pj_ioqueue_op_key_t *op_key,
																			const void *data,
																			pj_ssize_t *length,
																			pj_uint32_t flags,
																			const pj_sockaddr_t *addr,
																			int addrlen)
{
	struct write_operation *write_op;
	unsigned retry;
	pj_bool_t restart_retry = PJ_FALSE;
	pj_status_t status;
	pj_ssize_t sent;

	PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
	PJ_CHECK_STACK();

#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
	PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
retry_on_restart:
#else
	PJ_UNUSED_ARG(restart_retry);
#endif
	/* Check if key is closing. */
	if (IS_CLOSING(key))
		return PJ_ECANCELLED;

	/* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */
	flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

	/* Fast track:
	*   Try to send data immediately, only if there's no pending write!
	* Note:
	*  We are speculating that the list is empty here without properly
	*  acquiring ioqueue's mutex first. This is intentional, to maximize
	*  performance via parallelism.
	*
	*  This should be safe, because:
	*      - by convention, we require caller to make sure that the
	*        key is not unregistered while other threads are invoking
	*        an operation on the same key.
	*      - pj_list_empty() is safe to be invoked by multiple threads,
	*        even when other threads are modifying the list.
	*/
	if (pj_list_empty(&key->write_list)) {
		/*
		* See if data can be sent immediately.
		*/
		sent = *length;
		status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
		if (status == PJ_SUCCESS) {
			/* Success! */
			*length = sent;
			return PJ_SUCCESS;
		} else {
			/* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
			* the error to caller.
			*/
			if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
	PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
				/* Special treatment for dead UDP sockets here, see ticket #1107 */
				if (status==PJ_STATUS_FROM_OS(EPIPE) && !IS_CLOSING(key) &&
					key->fd_type==pj_SOCK_DGRAM() && !restart_retry)
				{
					PJ_PERROR(4,(THIS_FILE, status,
						"Send error for socket %d, retrying",
						key->fd));
					replace_udp_sock(key);
					restart_retry = PJ_TRUE;
					goto retry_on_restart;
				}
#endif

				return status;
			}
			status = status;
		}
	}

	/*
	* Check that address storage can hold the address parameter.
	*/
	PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG);

	/*
	* Schedule asynchronous send.
	*/
	write_op = (struct write_operation*)op_key;

	/* Spin if write_op has pending operation */
	for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry)
		pj_thread_sleep(5);

	/* Last chance */
	if (write_op->op) {
		/* Unable to send packet because there is already pending write on the
		* write_op. We could not put the operation into the write_op
		* because write_op already contains a pending operation! And
		* we could not send the packet directly with sendto() either,
		* because that will break the order of the packet. So we can
		* only return error here.
		*
		* This could happen for example in multithreads program,
		* where polling is done by one thread, while other threads are doing
		* the sending only. If the polling thread runs on lower priority
		* than the sending thread, then it's possible that the pending
		* write flag is not cleared in-time because clearing is only done
		* during polling. 
		*
		* Aplication should specify multiple write operation keys on
		* situation like this.
		*/
		//pj_assert(!"ioqueue: there is pending operation on this key!");
		return PJ_EBUSY;
	}

	write_op->op = PJ_IOQUEUE_OP_SEND_TO;
	write_op->buf = (char*)data;
	write_op->size = *length;
	write_op->written = 0;
	write_op->flags = flags;
	pj_memcpy(&write_op->rmt_addr, addr, addrlen);
	write_op->rmt_addrlen = addrlen;

	pj_mutex_lock(key->mutex);
	/* Check again. Handle may have been closed after the previous check
	* in multithreaded app. If we add bad handle to the set it will
	* corrupt the ioqueue set. See #913
	*/
	if (IS_CLOSING(key)) {
		pj_mutex_unlock(key->mutex);
		return PJ_ECANCELLED;
	}
	pj_list_insert_before(&key->write_list, write_op);
	ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
	pj_mutex_unlock(key->mutex);

	return PJ_EPENDING;
}
Ejemplo n.º 6
0
PJ_END_DECL
#endif

static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
{
#if PJ_HAS_THREADS
    pthread_mutexattr_t attr;
    int rc;

    PJ_CHECK_STACK();

    rc = pthread_mutexattr_init(&attr);
    if (rc != 0)
	return PJ_RETURN_OS_ERROR(rc);

    if (type == PJ_MUTEX_SIMPLE) {
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
    defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
       defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
	/* Nothing to do, default is simple */
#else
	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
#endif
    } else {
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
     defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
       defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
	// Phil Torre <*****@*****.**>:
	// The RTEMS implementation of POSIX mutexes doesn't include
	// pthread_mutexattr_settype(), so what follows is a hack
	// until I get RTEMS patched to support the set/get functions.
	//
	// More info:
	//   newlib's pthread also lacks pthread_mutexattr_settype(),
	//   but it seems to have mutexattr.recursive.
	PJ_TODO(FIX_RTEMS_RECURSIVE_MUTEX_TYPE)
	attr.recursive = 1;
#else
	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#endif
    }

    if (rc != 0) {
	return PJ_RETURN_OS_ERROR(rc);
    }

    rc = pthread_mutex_init(&mutex->mutex, &attr);
    if (rc != 0) {
	return PJ_RETURN_OS_ERROR(rc);
    }

    rc = pthread_mutexattr_destroy(&attr);
    if (rc != 0) {
	pj_status_t status = PJ_RETURN_OS_ERROR(rc);
	pthread_mutex_destroy(&mutex->mutex);
	return status;
    }

#if PJ_DEBUG
    /* Set owner. */
    mutex->nesting_level = 0;
    mutex->owner = NULL;
    mutex->owner_name[0] = '\0';
#endif

    /* Set name. */
    if (!name) {
	name = "mtx%p";
    }
    if (strchr(name, '%')) {
	pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
    } else {
	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
    }

    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
    return PJ_SUCCESS;
#else /* PJ_HAS_THREADS */
    return PJ_SUCCESS;
#endif
}
Ejemplo n.º 7
0
/*
* pj_ioqueue_send()
*
* Start asynchronous send() to the descriptor.
*/
PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
																		pj_ioqueue_op_key_t *op_key,
																		const void *data,
																		pj_ssize_t *length,
																		unsigned flags)
{
	struct write_operation *write_op;
	pj_status_t status;
	unsigned retry;
	pj_ssize_t sent;

	PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
	PJ_CHECK_STACK();

	/* Check if key is closing. */
	if (IS_CLOSING(key))
		return PJ_ECANCELLED;

	/* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write. */
	flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

	/* Fast track:
	*   Try to send data immediately, only if there's no pending write!
	* Note:
	*  We are speculating that the list is empty here without properly
	*  acquiring ioqueue's mutex first. This is intentional, to maximize
	*  performance via parallelism.
	*
	*  This should be safe, because:
	*      - by convention, we require caller to make sure that the
	*        key is not unregistered while other threads are invoking
	*        an operation on the same key.
	*      - pj_list_empty() is safe to be invoked by multiple threads,
	*        even when other threads are modifying the list.
	*/
	if (pj_list_empty(&key->write_list)) {
		/*
		* See if data can be sent immediately.
		*/
		sent = *length;
		status = pj_sock_send(key->fd, data, &sent, flags);
		if (status == PJ_SUCCESS) {
			/* Success! */
			*length = sent;
			return PJ_SUCCESS;
		} else {
			/* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
			* the error to caller.
			*/
			if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
				return status;
			}
		}
	}

	/*
	* Schedule asynchronous send.
	*/
	write_op = (struct write_operation*)op_key;

	/* Spin if write_op has pending operation */
	for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry)
		pj_thread_sleep(0);

	/* Last chance */
	if (write_op->op) {
		/* Unable to send packet because there is already pending write in the
		* write_op. We could not put the operation into the write_op
		* because write_op already contains a pending operation! And
		* we could not send the packet directly with send() either,
		* because that will break the order of the packet. So we can
		* only return error here.
		*
		* This could happen for example in multithreads program,
		* where polling is done by one thread, while other threads are doing
		* the sending only. If the polling thread runs on lower priority
		* than the sending thread, then it's possible that the pending
		* write flag is not cleared in-time because clearing is only done
		* during polling. 
		*
		* Aplication should specify multiple write operation keys on
		* situation like this.
		*/
		//pj_assert(!"ioqueue: there is pending operation on this key!");
		return PJ_EBUSY;
	}

	write_op->op = PJ_IOQUEUE_OP_SEND;
	write_op->buf = (char*)data;
	write_op->size = *length;
	write_op->written = 0;
	write_op->flags = flags;

	pj_mutex_lock(key->mutex);
	/* Check again. Handle may have been closed after the previous check
	* in multithreaded app. If we add bad handle to the set it will
	* corrupt the ioqueue set. See #913
	*/
	if (IS_CLOSING(key)) {
		pj_mutex_unlock(key->mutex);
		return PJ_ECANCELLED;
	}
	pj_list_insert_before(&key->write_list, write_op);
	ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
	pj_mutex_unlock(key->mutex);

	return PJ_EPENDING;
}
Ejemplo n.º 8
0
/*
* pj_ioqueue_recvfrom()
*
* Start asynchronous recvfrom() from the socket.
*/
PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
																				pj_ioqueue_op_key_t *op_key,
																				void *buffer,
																				pj_ssize_t *length,
																				unsigned flags,
																				pj_sockaddr_t *addr,
																				int *addrlen)
{
	struct read_operation *read_op;

	PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
	PJ_CHECK_STACK();

	/* Check if key is closing. */
	if (IS_CLOSING(key))
		return PJ_ECANCELLED;

	read_op = (struct read_operation*)op_key;
	read_op->op = PJ_IOQUEUE_OP_NONE;

	/* Try to see if there's data immediately available. 
	*/
	if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
		pj_status_t status;
		pj_ssize_t size;

		size = *length;
		status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
			addr, addrlen);
		if (status == PJ_SUCCESS) {
			/* Yes! Data is available! */
			*length = size;
			return PJ_SUCCESS;
		} else {
			/* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
			* the error to caller.
			*/
			if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
				return status;
		}
	}

	flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

	/*
	* No data is immediately available.
	* Must schedule asynchronous operation to the ioqueue.
	*/
	read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
	read_op->buf = buffer;
	read_op->size = *length;
	read_op->flags = flags;
	read_op->rmt_addr = addr;
	read_op->rmt_addrlen = addrlen;

	pj_mutex_lock(key->mutex);
	/* Check again. Handle may have been closed after the previous check
	* in multithreaded app. If we add bad handle to the set it will
	* corrupt the ioqueue set. See #913
	*/
	if (IS_CLOSING(key)) {
		pj_mutex_unlock(key->mutex);
		return PJ_ECANCELLED;
	}
	pj_list_insert_before(&key->read_list, read_op);
	ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
	pj_mutex_unlock(key->mutex);

	return PJ_EPENDING;
}
Ejemplo n.º 9
0
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
{
    pj_caching_pool *cp = (pj_caching_pool*)pf;
    pj_size_t pool_capacity;
    unsigned i;

    PJ_CHECK_STACK();

    PJ_ASSERT_ON_FAIL(pf && pool, return);

    pj_lock_acquire(cp->lock);

#if PJ_SAFE_POOL
    /* Make sure pool is still in our used list */
    if (pj_list_find_node(&cp->used_list, pool) != pool) {
	pj_assert(!"Attempt to destroy pool that has been destroyed before");
	return;
    }
#endif

    /* Erase from the used list. */
    pj_list_erase(pool);

    /* Decrement used count. */
    --cp->used_count;

    pool_capacity = pj_pool_get_capacity(pool);

    /* Destroy the pool if the size is greater than our size or if the total
     * capacity in our recycle list (plus the size of the pool) exceeds 
     * maximum capacity.
   . */
    if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
	cp->capacity + pool_capacity > cp->max_capacity)
    {
	pj_pool_destroy_int(pool);
	pj_lock_release(cp->lock);
	return;
    }

    /* Reset pool. */
    PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 
	       pool_capacity, pj_pool_get_used_size(pool), 
	       pj_pool_get_used_size(pool)*100/pool_capacity));
    pj_pool_reset(pool);

    pool_capacity = pj_pool_get_capacity(pool);

    /*
     * Otherwise put the pool in our recycle list.
     */
    i = (unsigned) (unsigned long) (pj_ssize_t) pool->factory_data;

    pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE);
    if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) {
	/* Something has gone wrong with the pool. */
	pj_pool_destroy_int(pool);
	pj_lock_release(cp->lock);
	return;
    }

    pj_list_insert_after(&cp->free_list[i], pool);
    cp->capacity += pool_capacity;

    pj_lock_release(cp->lock);
}
Ejemplo n.º 10
0
static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
					      const char *name, 
					      pj_size_t initial_size, 
					      pj_size_t increment_sz, 
					      pj_pool_callback *callback)
{
    pj_caching_pool *cp = (pj_caching_pool*)pf;
    pj_pool_t *pool;
    int idx;

    PJ_CHECK_STACK();

    pj_lock_acquire(cp->lock);

    /* Use pool factory's policy when callback is NULL */
    if (callback == NULL) {
	callback = pf->policy.callback;
    }

    /* Search the suitable size for the pool. 
     * We'll just do linear search to the size array, as the array size itself
     * is only a few elements. Binary search I suspect will be less efficient
     * for this purpose.
     */
    if (initial_size <= pool_sizes[START_SIZE]) {
	for (idx=START_SIZE-1; 
	     idx >= 0 && pool_sizes[idx] >= initial_size;
	     --idx)
	    ;
	++idx;
    } else {
	for (idx=START_SIZE+1; 
	     idx < PJ_CACHING_POOL_ARRAY_SIZE && 
		  pool_sizes[idx] < initial_size;
	     ++idx)
	    ;
    }

    /* Check whether there's a pool in the list. */
    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
	/* No pool is available. */
	/* Set minimum size. */
	if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
	    initial_size =  pool_sizes[idx];

	/* Create new pool */
	pool = pj_pool_create_int(&cp->factory, name, initial_size, 
				  increment_sz, callback);
	if (!pool) {
	    pj_lock_release(cp->lock);
	    return NULL;
	}

    } else {
	/* Get one pool from the list. */
	pool = (pj_pool_t*) cp->free_list[idx].next;
	pj_list_erase(pool);

	/* Initialize the pool. */
	pj_pool_init_int(pool, name, increment_sz, callback);

	/* Update pool manager's free capacity. */
	if (cp->capacity > pj_pool_get_capacity(pool)) {
	    cp->capacity -= pj_pool_get_capacity(pool);
	} else {
	    cp->capacity = 0;
	}

	PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
    }

    /* Put in used list. */
    pj_list_insert_before( &cp->used_list, pool );

    /* Mark factory data */
    pool->factory_data = (void*) (pj_ssize_t) idx;

    /* Increment used count. */
    ++cp->used_count;

    pj_lock_release(cp->lock);
    return pool;
}
Ejemplo n.º 11
0
/*
 * Receive data.
 */
PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
				     void *buf,
				     pj_ssize_t *len,
				     unsigned flags,
				     pj_sockaddr_t *from,
				     int *fromlen)
{
    PJ_CHECK_STACK();

    PJ_ASSERT_RETURN(sock && buf && len && from && fromlen, PJ_EINVAL);
    PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
    PJ_ASSERT_RETURN(*fromlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);

    // Return failure if access point is marked as down by app.
    PJ_SYMBIAN_CHECK_CONNECTION();

    CPjSocket *pjSock = (CPjSocket*)sock;
    RSocket &rSock = pjSock->Socket();

    if (pjSock->Reader()) {
	CPjSocketReader *reader = pjSock->Reader();

	while (reader->IsActive() && !reader->HasData()) {
	    User::WaitForAnyRequest();
	}

	if (reader->HasData()) {
	    TPtr8 data((TUint8*)buf, (TInt)*len);
	    TInetAddr inetAddr;

	    reader->ReadData(data, &inetAddr);

	    *len = data.Length();

	    if (from && fromlen) {
		return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, 
					    fromlen);
	    } else {
	    	return PJ_SUCCESS;
	    }
	}
    }

    TInetAddr inetAddr;
    TRequestStatus reqStatus;
    TSockXfrLength recvLen;
    TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);

    rSock.RecvFrom(data, inetAddr, flags, reqStatus, recvLen);
    User::WaitForRequest(reqStatus);

    if (reqStatus == KErrNone) {
	//*len = (TInt)recvLen.Length();
	*len = data.Length();
	return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen);
    } else {
	*len = -1;
	*fromlen = -1;
	return PJ_RETURN_OS_ERROR(reqStatus.Int());
    }
}