/* * 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 }
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; }
/* * 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 }
/* * pj_getpid(void) */ pj_uint32_t pj_getpid(void) { PJ_CHECK_STACK(); return getpid(); }
/* * 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; }
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 }
/* * 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; }
/* * 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; }
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); }
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; }
/* * 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()); } }