Beispiel #1
0
void
_PR_MD_RESTORE_CONTEXT(PRThread *thread)
{
    PRThread *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );

    /* The user-level code for yielding will happily add ourselves to the runq
     * and then switch to ourselves; the NT fibers can't handle switching to 
     * ourselves.
     */
    if (thread != me) {
        SetLastError(thread->md.fiber_last_error);
        _MD_SET_CURRENT_THREAD(thread);
        _PR_MD_SET_LAST_THREAD(me);
        thread->no_sched = 1;
        SwitchToFiber(thread->md.fiber_id);
        POST_SWITCH_WORK();
    }
}
Beispiel #2
0
PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
{
    PRCList *q;
    PRIntn is;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);

    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
	_PR_MD_LOCK( &(cvar->ilock) );
    q = cvar->condQ.next;
    while (q != &cvar->condQ) {
		PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
		_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
		q = q->next;
    }
	_PR_MD_UNLOCK( &(cvar->ilock) );
    if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);

    return PR_SUCCESS;
}  /* PRP_NakedBroadcast */
Beispiel #3
0
static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
{
	PRInt32 rv;
	PRUint32 al;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

	al = sizeof(PRNetAddr);
	rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
	return rv;
}
Beispiel #4
0
PRInt32
_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
{
    PRInt32 f = fd->secret->md.osfd;
    PRInt32 bytes;
    int rv;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    
    rv = WriteFile((HANDLE)f,
            buf,
            len,
            &bytes,
            NULL );
            
    if (rv == 0) 
    {
		_PR_MD_MAP_WRITE_ERROR(GetLastError());
        return -1;
    }
    return bytes;
} /* --- end _PR_MD_WRITE() --- */
Beispiel #5
0
static PRInt32 PR_CALLBACK SocketSendTo(
    PRFileDesc *fd, const void *buf, PRInt32 amount,
    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
{
	PRInt32 temp, count;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

#if defined(_PR_INET6)
	PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
#else
	PR_ASSERT(addr->raw.family == AF_INET);
#endif

	count = 0;
	while (amount > 0) {
		temp = _PR_MD_SENDTO(fd, buf, amount, flags,
		    addr, PR_NETADDR_SIZE(addr), timeout);
		if (temp < 0) {
					count = -1;
					break;
				}
		count += temp;
		if (fd->secret->nonblocking) {
			break;
		}
		buf = (const void*) ((const char*)buf + temp);
		amount -= temp;
	}
	return count;
}
Beispiel #6
0
PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
PRIntervalTime timeout)
{
	PRInt32 osfd;
	PRFileDesc *fd2;
	PRIntn al;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	PRNetAddr addrCopy;

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return 0;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return 0;
	}

		if (addr == NULL) {
			addr = &addrCopy;
		}
		al = PR_NETADDR_SIZE(addr);
		osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
		if (osfd == -1) {
			return 0;
		}

	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
	if (!fd2) {
		_PR_MD_CLOSE_SOCKET(osfd);
	} else {
		fd2->secret->nonblocking = fd->secret->nonblocking;
		fd2->secret->md.io_model_committed = PR_TRUE;
	        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
        	fd2->secret->md.accepted_socket = PR_TRUE;
        	memcpy(&fd2->secret->md.peer_addr, addr, al);
	}
	return fd2;
}
_MD_WakeupWaiter(PRThread *thread)
{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRInt32 pid, rv;
    PRIntn is;

	PR_ASSERT(_pr_md_idle_cpus >= 0);
    if (thread == NULL) {
		if (_pr_md_idle_cpus)
        	_MD_Wakeup_CPUs();
    } else if (!_PR_IS_NATIVE_THREAD(thread)) {
		/*
		 * If the thread is on my cpu's runq there is no need to
		 * wakeup any cpus
		 */
		if (!_PR_IS_NATIVE_THREAD(me)) {
			if (me->cpu != thread->cpu) {
				if (_pr_md_idle_cpus)
        			_MD_Wakeup_CPUs();
			}
		} else {
			if (_pr_md_idle_cpus)
        		_MD_Wakeup_CPUs();
		}
    } else {
		PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
		if (!_PR_IS_NATIVE_THREAD(me))
			_PR_INTSOFF(is);

		pthread_mutex_lock(&thread->md.pthread_mutex);
		thread->md.wait++;
		rv = pthread_cond_signal(&thread->md.pthread_cond);
		PR_ASSERT(rv == 0);
		pthread_mutex_unlock(&thread->md.pthread_mutex);

		if (!_PR_IS_NATIVE_THREAD(me))
			_PR_FAST_INTSON(is);
    } 
    return PR_SUCCESS;
}
static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
	PRInt32 temp, count;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

	count = 0;
	while (amount > 0) {
		PR_LOG(_pr_io_lm, PR_LOG_MAX,
		    ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d",
		    fd, fd->secret->md.osfd, buf, amount));
		temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
		if (temp < 0) {
					count = -1;
					break;
				}

		count += temp;
		if (fd->secret->nonblocking) {
			break;
		}
		buf = (const void*) ((const char*)buf + temp);

		amount -= temp;
	}
	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
	return count;
}
Beispiel #9
0
void _PR_DumpThreads(PRFileDesc *fd)
{
    PRThread *t;
    PRIntn i;

    _PR_DumpPrintf(fd, "Current Thread:\n");
    t = _PR_MD_CURRENT_THREAD();
    _PR_DumpThread(fd, t);

    _PR_DumpPrintf(fd, "Runnable Threads:\n");
    for (i = 0; i < 32; i++) {
        DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]);
    }

    _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n");
    DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu));

    _PR_DumpPrintf(fd, "CondVar wait Threads:\n");
    DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu));

    _PR_DumpPrintf(fd, "Suspended Threads:\n");
    DumpThreadQueue(fd, &_PR_SUSPENDQ(t->cpu));
}
Beispiel #10
0
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
PRIntervalTime timeout)
{
	PRInt32 rv;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d",
		    						fd, fd->secret->md.osfd, buf, amount));
	rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
		rv, PR_GetError(), PR_GetOSError()));
	return rv;
}
Beispiel #11
0
void _MD_InitNetAccess()
{
	OSErr		err;
	OSStatus    errOT;
	PRBool 		hasOTTCPIP = PR_FALSE;
	PRBool 		hasOT = PR_FALSE;
	long 		gestaltResult;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	
	err = Gestalt(gestaltOpenTpt, &gestaltResult);
	if (err == noErr)
		if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
			hasOT = PR_TRUE;
	
	if (hasOT)
		if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
			hasOTTCPIP = PR_TRUE;
		
	PR_ASSERT(hasOTTCPIP == PR_TRUE);

	errOT = InitOpenTransport();
	PR_ASSERT(err == kOTNoError);

	sSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &errOT);
	if (errOT != kOTNoError) return;	/* no network -- oh well */
	PR_ASSERT((sSvcRef != NULL) && (errOT == kOTNoError));

    /* Install notify function for DNR Address To String completion */
	errOT = OTInstallNotifier(sSvcRef, NotifierRoutine, me);
	PR_ASSERT(errOT == kOTNoError);

    /* Put us into async mode */
	errOT = OTSetAsynchronous(sSvcRef);
	PR_ASSERT(errOT == kOTNoError);

/* XXX Does not handle absence of open tpt and tcp yet! */
}
static PRInt32 PR_CALLBACK SocketSendFile(
    PRFileDesc *sd, PRSendFileData *sfd,
    PRTransmitFileFlags flags, PRIntervalTime timeout)
{
	PRInt32 rv;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}
	/* The socket must be in blocking mode. */
	if (sd->secret->nonblocking) {
		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
		return -1;
	}
#if defined(WINNT)
	rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
		/*
		 * This should be kept the same as SocketClose, except
		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
		 * not be called because the socket will be recycled.
		 */
		PR_FreeFileDesc(sd);
	}
#else
	rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
#endif	/* WINNT */

	return rv;
}
Beispiel #13
0
PR_IMPLEMENT(PRStatus) PR_SetThreadExit(PRUintn index, PRThreadExit func, void *arg)
{
    _PRPerThreadExit *pte;
    PRThread *thread = _PR_MD_CURRENT_THREAD();

    if (index >= thread->numExits) {
	if (thread->ptes) {
	    thread->ptes = (_PRPerThreadExit*)
		PR_REALLOC(thread->ptes, (index+1) * sizeof(_PRPerThreadExit));
	} else {
	    thread->ptes = (_PRPerThreadExit*)
	        PR_CALLOC(index+1 * sizeof(_PRPerThreadExit));
	}
	if (!thread->ptes) {
	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
	    return PR_FAILURE;
	}
	thread->numExits = index + 1;
    }
    pte = &thread->ptes[index];
    pte->func = func;
    pte->arg = arg;
    return PR_SUCCESS;
}
Beispiel #14
0
static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount)
{
    PRInt32 rv = 0;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (_PR_PENDING_INTERRUPT(me)) {
 		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		rv = -1;
    }
    if (_PR_IO_PENDING(me)) {
        PR_SetError(PR_IO_PENDING_ERROR, 0);
	rv = -1;
    }
    if (rv == -1)
    	return rv;

	rv = _PR_MD_READ(fd, buf, amount);
	if (rv < 0) {
		PR_ASSERT(rv == -1);
	}
    PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv));
    return rv;
}
/*
** Unlock the lock.
*/
PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
{
    PRCList *q;
    PRThreadPriority pri, boost;
    PRIntn is;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT(lock != NULL);
    PR_ASSERT(lock->owner == me);
    PR_ASSERT(me != suspendAllThread); 
    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
    if (lock->owner != me) {
        return PR_FAILURE;
    }

#ifdef _PR_GLOBAL_THREADS_ONLY 
    lock->owner = 0;
    _PR_MD_UNLOCK(&lock->ilock);
    return PR_SUCCESS;
#else  /* _PR_GLOBAL_THREADS_ONLY */

	if (_native_threads_only) {
		lock->owner = 0;
		_PR_MD_UNLOCK(&lock->ilock);
		return PR_SUCCESS;
	}

    if (!_PR_IS_NATIVE_THREAD(me))
    	_PR_INTSOFF(is);
    _PR_LOCK_LOCK(lock);

	/* Remove the lock from the owning thread's lock list */
    PR_REMOVE_LINK(&lock->links);
    pri = lock->priority;
    boost = lock->boostPriority;
    if (boost > pri) {
        /*
        ** We received a priority boost during the time we held the lock.
        ** We need to figure out what priority to move to by scanning
        ** down our list of lock's that we are still holding and using
        ** the highest boosted priority found.
        */
        q = me->lockList.next;
        while (q != &me->lockList) {
            PRLock *ll = _PR_LOCK_PTR(q);
            if (ll->boostPriority > pri) {
                pri = ll->boostPriority;
            }
            q = q->next;
        }
        if (pri != me->priority) {
            _PR_SetThreadPriority(me, pri);
        }
    }

    /* Unblock the first waiting thread */
    q = lock->waitQ.next;
    if (q != &lock->waitQ)
        _PR_UnblockLockWaiter(lock);
    lock->boostPriority = PR_PRIORITY_LOW;
    lock->owner = 0;
    _PR_LOCK_UNLOCK(lock);
    if (!_PR_IS_NATIVE_THREAD(me))
    	_PR_INTSON(is);
    return PR_SUCCESS;
#endif  /* _PR_GLOBAL_THREADS_ONLY */
}
Beispiel #16
0
PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
{
	OSStatus err;
	PRInt32 osfd = fd->secret->md.osfd;
	EndpointRef endpoint = (EndpointRef) osfd;
	TOptMgmt cmd;
	TOption *opt;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
	
	if (endpoint == NULL) {
		err = kEBADFErr;
		goto ErrorExit;
	}
	
	/* 
	OT wants IPPROTO_IP for level and not XTI_GENERIC.  SO_REUSEADDR and SO_KEEPALIVE 
	are equated to IP level and TCP level options respectively and hence we need to set 
	the level correctly.
	*/
	if (level == SOL_SOCKET) {
		if (optname == SO_REUSEADDR)
			level = IPPROTO_IP;
		else if (optname == SO_KEEPALIVE)
			level = INET_TCP;
	}

	opt = (TOption *)&optionBuffer[0];
	opt->len = kOTOptionHeaderSize + optlen;

	/* special case adjustments for length follow */
	if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */
		opt->len = kOTOptionHeaderSize + sizeof(t_kpalive);
	if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */
		opt->len = kOTOneByteOptionSize;
	if (optname == IP_TOS && level == IPPROTO_IP)
		opt->len = kOTOneByteOptionSize;

	opt->level = level;
	opt->name = optname;
	opt->status = 0;
	
	cmd.opt.len = opt->len;
	cmd.opt.maxlen = sizeof(optionBuffer);
	cmd.opt.buf = (UInt8*)optionBuffer;
	
	optionBuffer[opt->len] = 0;
	
	cmd.flags = T_NEGOTIATE;

	switch (optname) {
		case SO_LINGER:
			*((t_linger*)&opt->value) = *((t_linger*)optval);
			break;
		case SO_REUSEADDR:
		case TCP_NODELAY:
		case SO_RCVBUF:
		case SO_SNDBUF:
			*((PRIntn*)&opt->value) = *((PRIntn*)optval);
			break;
		case IP_MULTICAST_LOOP:
			if (*optval != 0)
				opt->value[0] = T_YES;
			else
				opt->value[0] = T_NO;
			break;
		case SO_KEEPALIVE:
			{
			t_kpalive *kpalive = (t_kpalive *)&opt->value;
			
			kpalive->kp_onoff = *((long*)optval);
			kpalive->kp_timeout = 10; /* timeout in minutes */
			break;
			}
		case IP_TTL:
			*((unsigned char*)&opt->value) = *((PRUintn*)optval);
			break;
		case IP_MULTICAST_TTL:
			*((unsigned char*)&opt->value) = *optval;
			break;
		case IP_ADD_MEMBERSHIP:
		case IP_DROP_MEMBERSHIP:
			{
			/* struct ip_mreq and TIPAddMulticast are the same size and optval 
			   is pointing to struct ip_mreq */
			*((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval);
			break;
			}
		case IP_MULTICAST_IF:
			{
			*((PRUint32*)&opt->value) = *((PRUint32*)optval);
			break;
			}
		/*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
		case TCP_MAXSEG:
			if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
				*((PRIntn*)&opt->value) = *((PRIntn*)optval);
			} else { /* it is IP_TOS */
				*((unsigned char*)&opt->value) = *((PRUintn*)optval);
			}
			break;
		default:
			PR_ASSERT(0);
			break;	
	}
	
	PrepareThreadForAsyncIO(me, endpoint, osfd);    

	err = OTOptionManagement(endpoint, &cmd, &cmd);
	if (err != kOTNoError)
		goto ErrorExit;

	WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
		err = kEOPNOTSUPPErr;
		goto ErrorExit;
	}
	
	if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
		err = kEOPNOTSUPPErr;
		goto ErrorExit;
	}

	PR_ASSERT(opt->status == T_SUCCESS);

	return PR_SUCCESS;

ErrorExit:
	macsock_map_error(err);
    return PR_FAILURE;
}
/*
** Lock the lock.
*/
PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRIntn is;
    PRThread *t;
    PRCList *q;

    PR_ASSERT(me != suspendAllThread); 
    PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
    PR_ASSERT(lock != NULL);
#ifdef _PR_GLOBAL_THREADS_ONLY 
    _PR_MD_LOCK(&lock->ilock);
    PR_ASSERT(lock->owner == 0);
    lock->owner = me;
    return;
#else  /* _PR_GLOBAL_THREADS_ONLY */

	if (_native_threads_only) {
		_PR_MD_LOCK(&lock->ilock);
		PR_ASSERT(lock->owner == 0);
		lock->owner = me;
		return;
	}

    if (!_PR_IS_NATIVE_THREAD(me))
    	_PR_INTSOFF(is);

    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);

retry:
    _PR_LOCK_LOCK(lock);
    if (lock->owner == 0) {
        /* Just got the lock */
        lock->owner = me;
        lock->priority = me->priority;
		/* Add the granted lock to this owning thread's lock list */
        PR_APPEND_LINK(&lock->links, &me->lockList);
        _PR_LOCK_UNLOCK(lock);
    	if (!_PR_IS_NATIVE_THREAD(me))
        	_PR_FAST_INTSON(is);
        return;
    }

    /* If this thread already owns this lock, then it is a deadlock */
    PR_ASSERT(lock->owner != me);

    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);

#if 0
    if (me->priority > lock->owner->priority) {
        /*
        ** Give the lock owner a priority boost until we get the
        ** lock. Record the priority we boosted it to.
        */
        lock->boostPriority = me->priority;
        _PR_SetThreadPriority(lock->owner, me->priority);
    }
#endif

    /* 
    Add this thread to the asked for lock's list of waiting threads.  We
    add this thread thread in the right priority order so when the unlock
    occurs, the thread with the higher priority will get the lock.
    */
    q = lock->waitQ.next;
    if (q == &lock->waitQ || _PR_THREAD_CONDQ_PTR(q)->priority ==
      	_PR_THREAD_CONDQ_PTR(lock->waitQ.prev)->priority) {
		/*
		 * If all the threads in the lock waitQ have the same priority,
		 * then avoid scanning the list:  insert the element at the end.
		 */
		q = &lock->waitQ;
    } else {
		/* Sort thread into lock's waitQ at appropriate point */
		/* Now scan the list for where to insert this entry */
		while (q != &lock->waitQ) {
			t = _PR_THREAD_CONDQ_PTR(lock->waitQ.next);
			if (me->priority > t->priority) {
				/* Found a lower priority thread to insert in front of */
				break;
			}
			q = q->next;
		}
	}
    PR_INSERT_BEFORE(&me->waitQLinks, q);

	/* 
	Now grab the threadLock since we are about to change the state.  We have
	to do this since a PR_Suspend or PR_SetThreadPriority type call that takes
	a PRThread* as an argument could be changing the state of this thread from
	a thread running on a different cpu.
	*/

    _PR_THREAD_LOCK(me);
    me->state = _PR_LOCK_WAIT;
    me->wait.lock = lock;
    _PR_THREAD_UNLOCK(me);

    _PR_LOCK_UNLOCK(lock);

    _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
	goto retry;

#endif  /* _PR_GLOBAL_THREADS_ONLY */
}
Beispiel #18
0
/*
** Make the given thread wait for the given condition variable
*/
PRStatus _PR_WaitCondVar(
    PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
{
    PRIntn is;
    PRStatus rv = PR_SUCCESS;

    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));

#ifdef _PR_GLOBAL_THREADS_ONLY
    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    thread->wait.cvar = cvar;
    lock->owner = NULL;
    _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
    thread->wait.cvar = NULL;
    lock->owner = thread;
    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    return PR_SUCCESS;
#else  /* _PR_GLOBAL_THREADS_ONLY */

    if ( !_PR_IS_NATIVE_THREAD(thread))
    	_PR_INTSOFF(is);

    _PR_CVAR_LOCK(cvar);
    _PR_THREAD_LOCK(thread);

    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
    	_PR_CVAR_UNLOCK(cvar);
    	_PR_THREAD_UNLOCK(thread);
    	if ( !_PR_IS_NATIVE_THREAD(thread))
    		_PR_INTSON(is);
        return PR_FAILURE;
    }

    thread->state = _PR_COND_WAIT;
    thread->wait.cvar = cvar;

    /*
    ** Put the caller thread on the condition variable's wait Q
    */
    PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);

    /* Note- for global scope threads, we don't put them on the
     *       global sleepQ, so each global thread must put itself
     *       to sleep only for the time it wants to.
     */
    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
        _PR_SLEEPQ_LOCK(thread->cpu);
        _PR_ADD_SLEEPQ(thread, timeout);
        _PR_SLEEPQ_UNLOCK(thread->cpu);
    }
    _PR_CVAR_UNLOCK(cvar);
    _PR_THREAD_UNLOCK(thread);
   
    /* 
    ** Release lock protecting the condition variable and thereby giving time 
    ** to the next thread which can potentially notify on the condition variable
    */
    PR_Unlock(lock);

    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
	   ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));

    rv = _PR_MD_WAIT(thread, timeout);

    _PR_CVAR_LOCK(cvar);
    PR_REMOVE_LINK(&thread->waitQLinks);
    _PR_CVAR_UNLOCK(cvar);

    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
	   ("PR_Wait: cvar=%p done waiting", cvar));

    if ( !_PR_IS_NATIVE_THREAD(thread))
    	_PR_INTSON(is);

    /* Acquire lock again that we had just relinquished */
    PR_Lock(lock);

    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    return rv;
#endif  /* _PR_GLOBAL_THREADS_ONLY */
}
Beispiel #19
0
/*
** Expire condition variable waits that are ready to expire. "now" is the current
** time.
*/
void _PR_ClockInterrupt(void)
{
    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
    _PRCPU *cpu = me->cpu;
    PRIntervalTime elapsed, now;
 
    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
    /* Figure out how much time elapsed since the last clock tick */
    now = PR_IntervalNow();
    elapsed = now - cpu->last_clock;
    cpu->last_clock = now;

#ifndef XP_MAC
    PR_LOG(_pr_clock_lm, PR_LOG_MAX,
	   ("ExpireWaits: elapsed=%lld usec", elapsed));
#endif

    while(1) {
        _PR_SLEEPQ_LOCK(cpu);
        if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
            _PR_SLEEPQ_UNLOCK(cpu);
            break;
        }

        thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
        PR_ASSERT(thread->cpu == cpu);

        if (elapsed < thread->sleep) {
            thread->sleep -= elapsed;
            _PR_SLEEPQMAX(thread->cpu) -= elapsed;
            _PR_SLEEPQ_UNLOCK(cpu);
            break;
        }
        _PR_SLEEPQ_UNLOCK(cpu);

        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

        _PR_THREAD_LOCK(thread);

        if (thread->cpu != cpu) {
            /*
            ** The thread was switched to another CPU
            ** between the time we unlocked the sleep
            ** queue and the time we acquired the thread
            ** lock, so it is none of our business now.
            */
            _PR_THREAD_UNLOCK(thread);
            continue;
        }

        /*
        ** Consume this sleeper's amount of elapsed time from the elapsed
        ** time value. The next remaining piece of elapsed time will be
        ** available for the next sleeping thread's timer.
        */
        _PR_SLEEPQ_LOCK(cpu);
        PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
        if (thread->flags & _PR_ON_SLEEPQ) {
            _PR_DEL_SLEEPQ(thread, PR_FALSE);
            elapsed -= thread->sleep;
            _PR_SLEEPQ_UNLOCK(cpu);
        } else {
            /* Thread was already handled; Go get another one */
            _PR_SLEEPQ_UNLOCK(cpu);
            _PR_THREAD_UNLOCK(thread);
            continue;
        }

        /* Notify the thread waiting on the condition variable */
        if (thread->flags & _PR_SUSPENDING) {
		PR_ASSERT((thread->state == _PR_IO_WAIT) ||
				(thread->state == _PR_COND_WAIT));
            /*
            ** Thread is suspended and its condition timeout
            ** expired. Transfer thread from sleepQ to suspendQ.
            */
            thread->wait.cvar = NULL;
            _PR_MISCQ_LOCK(cpu);
            thread->state = _PR_SUSPENDED;
            _PR_ADD_SUSPENDQ(thread, cpu);
            _PR_MISCQ_UNLOCK(cpu);
        } else {
            if (thread->wait.cvar) {
                PRThreadPriority pri;

                /* Do work very similar to what _PR_NotifyThread does */
                PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );

                /* Make thread runnable */
                pri = thread->priority;
                thread->state = _PR_RUNNABLE;
                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));

                PR_ASSERT(thread->cpu == cpu);
                _PR_RUNQ_LOCK(cpu);
                _PR_ADD_RUNQ(thread, cpu, pri);
                _PR_RUNQ_UNLOCK(cpu);

                if (pri > me->priority)
                    _PR_SET_RESCHED_FLAG();

                thread->wait.cvar = NULL;

                _PR_MD_WAKEUP_WAITER(thread);

            } else if (thread->io_pending == PR_TRUE) {
                /* Need to put IO sleeper back on runq */
                int pri = thread->priority;

                thread->io_suspended = PR_TRUE;
#ifdef WINNT
				/*
				 * For NT, record the cpu on which I/O was issued
				 * I/O cancellation is done on the same cpu
				 */
                thread->md.thr_bound_cpu = cpu;
#endif

				PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
                PR_ASSERT(thread->cpu == cpu);
                thread->state = _PR_RUNNABLE;
                _PR_RUNQ_LOCK(cpu);
                _PR_ADD_RUNQ(thread, cpu, pri);
                _PR_RUNQ_UNLOCK(cpu);
            }
        }
        _PR_THREAD_UNLOCK(thread);
    }
}
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
PRInt32 iov_size, PRIntervalTime timeout)
{
	PRThread *me = _PR_MD_CURRENT_THREAD();
	int w = 0;
	const PRIOVec *tmp_iov;
#define LOCAL_MAXIOV    8
	PRIOVec local_iov[LOCAL_MAXIOV];
	PRIOVec *iov_copy = NULL;
	int tmp_out;
	int index, iov_cnt;
	int count=0, sz = 0;    /* 'count' is the return value. */

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

    /*
     * Assume the first writev will succeed.  Copy iov's only on
     * failure.
     */
    tmp_iov = iov;
    for (index = 0; index < iov_size; index++)
        sz += iov[index].iov_len;

	iov_cnt = iov_size;

	while (sz > 0) {

		w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
		if (w < 0) {
			count = -1;
			break;
		}
		count += w;
		if (fd->secret->nonblocking) {
			break;
		}
		sz -= w;

		if (sz > 0) {
			/* find the next unwritten vector */
			for ( index = 0, tmp_out = count;
				tmp_out >= iov[index].iov_len;
				tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */

			if (tmp_iov == iov) {
				/*
				 * The first writev failed so we
				 * must copy iov's around.
				 * Avoid calloc/free if there
				 * are few enough iov's.
				 */
				if (iov_size - index <= LOCAL_MAXIOV)
					iov_copy = local_iov;
				else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
					sizeof *iov_copy)) == NULL) {
					PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
					return -1;
				}
				tmp_iov = iov_copy;
			}

			PR_ASSERT(tmp_iov == iov_copy);

			/* fill in the first partial read */
			iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
			iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
			index++;

			/* copy the remaining vectors */
			for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
				iov_copy[iov_cnt].iov_base = iov[index].iov_base;
				iov_copy[iov_cnt].iov_len = iov[index].iov_len;
			}
		}
	}

	if (iov_copy != local_iov)
		PR_DELETE(iov_copy);
	return count;
}
Beispiel #21
0
PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
{
	PRInt32 osfd = fd->secret->md.osfd;
	OSStatus err;
	EndpointRef endpoint = (EndpointRef) osfd;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	TBind bindReq;
	PRNetAddr bindAddr;
	PRInt32 newosfd = -1;
	EndpointRef newEndpoint;
	TCall call;
	PRNetAddr callAddr;

	if (endpoint == NULL) {
		err = kEBADFErr;
		goto ErrorExit;
	}
		
	memset(&call, 0 , sizeof(call));

	call.addr.maxlen = PR_NETADDR_SIZE(&callAddr);
	call.addr.len = PR_NETADDR_SIZE(&callAddr);
	call.addr.buf = (UInt8*) &callAddr;
	
	PrepareThreadForAsyncIO(me, endpoint, osfd);    

	err = OTListen (endpoint, &call);
	if (err != kOTNoError && (err != kOTNoDataErr || fd->secret->nonblocking)) {
    	me->io_pending = PR_FALSE;
		goto ErrorExit;
	}

	while (err == kOTNoDataErr) {
		WaitOnThisThread(me, timeout);
		err = me->md.osErrCode;
		if (err != kOTNoError)
			goto ErrorExit;

		PrepareThreadForAsyncIO(me, endpoint, osfd);    

		err = OTListen (endpoint, &call);
		if (err == kOTNoError)
			break;

		PR_ASSERT(err == kOTNoDataErr);
	}		

	newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
	if (newosfd == -1)
		return -1;

	newEndpoint = (EndpointRef)newosfd;
	
	// Bind to a local port; let the system assign it.

	bindAddr.inet.port = bindAddr.inet.ip = 0;

	bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
	bindReq.addr.len = 0;
	bindReq.addr.buf = (UInt8*) &bindAddr;
	bindReq.qlen = 0;
	
	PrepareThreadForAsyncIO(me, newEndpoint, newosfd);    

	err = OTBind(newEndpoint, &bindReq, NULL);
	if (err != kOTNoError)
		goto ErrorExit;

	WaitOnThisThread(me, timeout);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	PrepareThreadForAsyncIO(me, endpoint, newosfd);    

	err = OTAccept (endpoint, newEndpoint, &call);
	if (err != kOTNoError)
		goto ErrorExit;

	WaitOnThisThread(me, timeout);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	PR_ASSERT(me->md.cookie != NULL);

	if (addr != NULL)
		*addr = callAddr;
	if (addrlen != NULL)
		*addrlen = call.addr.len;

	return newosfd;

ErrorExit:
	if (newosfd != -1)
		_MD_closesocket(newosfd);
	macsock_map_error(err);
    return -1;
}
Beispiel #22
0
PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
{
	PRInt32 osfd = fd->secret->md.osfd;
	OSStatus err;
	EndpointRef endpoint = (EndpointRef) osfd;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	TCall sndCall;
	TBind bindReq;
	PRNetAddr bindAddr;

	if (endpoint == NULL) {
		err = kEBADFErr;
		goto ErrorExit;
	}
		
	if (addr == NULL) {
		err = kEFAULTErr;
		goto ErrorExit;
	}
		
	// Bind to a local port; let the system assign it.

	bindAddr.inet.port = bindAddr.inet.ip = 0;

	bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
	bindReq.addr.len = 0;
	bindReq.addr.buf = (UInt8*) &bindAddr;
	bindReq.qlen = 0;
	
	PrepareThreadForAsyncIO(me, endpoint, osfd);    

	err = OTBind(endpoint, &bindReq, NULL);
	if (err != kOTNoError)
		goto ErrorExit;

	WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	memset(&sndCall, 0 , sizeof(sndCall));

	sndCall.addr.maxlen = addrlen;
	sndCall.addr.len = addrlen;
	sndCall.addr.buf = (UInt8*) addr;
	
	PrepareThreadForAsyncIO(me, endpoint, osfd);    

	err = OTConnect (endpoint, &sndCall, NULL);
	if (err != kOTNoError && err != kOTNoDataErr)
		goto ErrorExit;
	if (err == kOTNoDataErr && fd->secret->nonblocking) {
		err = kEINPROGRESSErr;
    	me->io_pending = PR_FALSE;
		goto ErrorExit;
	}

	WaitOnThisThread(me, timeout);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	PR_ASSERT(me->md.cookie != NULL);

	err = OTRcvConnect(endpoint, NULL);
	PR_ASSERT(err == kOTNoError);

	return kOTNoError;

ErrorExit:
	macsock_map_error(err);
    return -1;
}
Beispiel #23
0
static void macsock_map_error(OSStatus err)
{
	_PR_MD_CURRENT_THREAD()->md.osErrCode = err;

	if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
	switch (IsEError(err) ? OSStatus2E(err) : err) {
		case EBADF:
			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
			break;
		case EADDRNOTAVAIL:
			PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
			break;
		case EINPROGRESS:
			PR_SetError(PR_IN_PROGRESS_ERROR, err);
			break;
		case EWOULDBLOCK:
		case EAGAIN:
			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
			break;
		case ENOTSOCK:
			PR_SetError(PR_NOT_SOCKET_ERROR, err);
			break;
		case ETIMEDOUT:
			PR_SetError(PR_IO_TIMEOUT_ERROR, err);
			break;
		case ECONNREFUSED:
			PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
			break;
		case ENETUNREACH:
			PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
			break;
		case EADDRINUSE:
			PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
			break;
		case EFAULT:
			PR_SetError(PR_ACCESS_FAULT_ERROR, err);
			break;
		case EINTR:
			PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
			break;
		case EINVAL:
			PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
			break;
		case EIO:
			PR_SetError(PR_IO_ERROR, err);
			break;
		case ENOENT:
			PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
			break;
		case ENXIO:
			PR_SetError(PR_IO_ERROR, err);
			break;
		case EPROTOTYPE:
			PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
			break;
		case EOPNOTSUPP:
			PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
			break;
		default:
			PR_SetError(PR_UNKNOWN_ERROR, err);
			break;
		}
	} else {
	PR_ASSERT(IsXTIError(err));
	switch (err) {
		case kOTNoDataErr:
		case kOTFlowErr:
			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
			break;
		default:
			PR_ASSERT(0);
			PR_SetError(PR_UNKNOWN_ERROR, err);
			break;
	    }
	}
}
Beispiel #24
0
PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
PRIntervalTime timeout)
{
	PRInt32 rv, count = 0;
	PRInt32 rlen;
	PRThread *me = _PR_MD_CURRENT_THREAD();
	char *buf = NULL;
#define _TRANSMITFILE_BUFSIZE	(16 * 1024)

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}

	buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE);
	if (buf == NULL) {
		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
		return -1;
	}

	/*
	 * send headers, first
	 */
	while (hlen) {
		rv =  PR_Send(sd, headers, hlen, 0, timeout);
		if (rv < 0) {
			/* PR_Send() has invoked PR_SetError(). */
			rv = -1;
			goto done;
		} else {
			count += rv;
			headers = (const void*) ((const char*)headers + rv);
			hlen -= rv;
		}
	}
	/*
	 * send file, next
	 */
	while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) {
		while (rlen) {
			char *bufptr = buf;

			rv =  PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT);
			if (rv < 0) {
				/* PR_Send() has invoked PR_SetError(). */
				rv = -1;
				goto done;
			} else {
				count += rv;
				bufptr = ((char*)bufptr + rv);
				rlen -= rv;
			}
		}
	}
	if (rlen == 0) {
		/*
		 * end-of-file
		 */
		if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
			PR_Close(sd);
		rv = count;
	} else {
		PR_ASSERT(rlen < 0);
		/* PR_Read() has invoked PR_SetError(). */
		rv = -1;
	}

done:
	if (buf)
		PR_DELETE(buf);
	return rv;
}
/*
**  If the current thread owns |lock|, this assertion is guaranteed to
**  succeed.  Otherwise, the behavior of this function is undefined.
*/
PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PR_ASSERT(lock->owner == me);
}
Beispiel #26
0
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_size,
PRIntervalTime timeout)
{
	PRThread *me = _PR_MD_CURRENT_THREAD();
	int w = 0;
	PRIOVec *tmp_iov = NULL;
	int tmp_out;
	int index, iov_cnt;
	int count=0, sz = 0;    /* 'count' is the return value. */
#if defined(XP_UNIX)
	struct timeval tv, *tvp;
	fd_set wd;

	FD_ZERO(&wd);
	if (timeout == PR_INTERVAL_NO_TIMEOUT)
		tvp = NULL;
	else if (timeout != PR_INTERVAL_NO_WAIT) {
		tv.tv_sec = PR_IntervalToSeconds(timeout);
		tv.tv_usec = PR_IntervalToMicroseconds(
		    timeout - PR_SecondsToInterval(tv.tv_sec));
		tvp = &tv;
	}
#endif

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

	tmp_iov = (PRIOVec *)PR_CALLOC(iov_size * sizeof(PRIOVec));
	if (!tmp_iov) {
		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
		return -1;
	}

	for (index=0; index<iov_size; index++) {
		sz += iov[index].iov_len;
		tmp_iov[index].iov_base = iov[index].iov_base;
		tmp_iov[index].iov_len = iov[index].iov_len;
	}
	iov_cnt = iov_size;

	while (sz > 0) {

		w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
		if (w < 0) {
					count = -1;
					break;
		}
		count += w;
		if (fd->secret->nonblocking) {
			break;
		}
		sz -= w;

		if (sz > 0) {
			/* find the next unwritten vector */
			for ( index = 0, tmp_out = count;
			    tmp_out >= iov[index].iov_len;
			    tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */


			/* fill in the first partial read */
			tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
			tmp_iov[0].iov_len = iov[index].iov_len - tmp_out;
			index++;

			/* copy the remaining vectors */
			for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
				tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
				tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
			}
		}
	}

	if (tmp_iov)
		PR_DELETE(tmp_iov);
	return count;
}
/*
** Unblock the first runnable waiting thread. Skip over
** threads that are trying to be suspended
** Note: Caller must hold _PR_LOCK_LOCK()
*/
void _PR_UnblockLockWaiter(PRLock *lock)
{
    PRThread *t = NULL;
    PRThread *me;
    PRCList *q;

    q = lock->waitQ.next;
    PR_ASSERT(q != &lock->waitQ);
    while (q != &lock->waitQ) {
        /* Unblock first waiter */
        t = _PR_THREAD_CONDQ_PTR(q);

		/* 
		** We are about to change the thread's state to runnable and for local
		** threads, we are going to assign a cpu to it.  So, protect thread's
		** data structure.
		*/
        _PR_THREAD_LOCK(t);

        if (t->flags & _PR_SUSPENDING) {
            q = q->next;
            _PR_THREAD_UNLOCK(t);
            continue;
        }

        /* Found a runnable thread */
	    PR_ASSERT(t->state == _PR_LOCK_WAIT);
	    PR_ASSERT(t->wait.lock == lock);
        t->wait.lock = 0;
        PR_REMOVE_LINK(&t->waitQLinks);         /* take it off lock's waitQ */

		/*
		** If this is a native thread, nothing else to do except to wake it
		** up by calling the machine dependent wakeup routine.
		**
		** If this is a local thread, we need to assign it a cpu and
		** put the thread on that cpu's run queue.  There are two cases to
		** take care of.  If the currently running thread is also a local
		** thread, we just assign our own cpu to that thread and put it on
		** the cpu's run queue.  If the the currently running thread is a
		** native thread, we assign the primordial cpu to it (on NT,
		** MD_WAKEUP handles the cpu assignment).  
		*/
		
        if ( !_PR_IS_NATIVE_THREAD(t) ) {

            t->state = _PR_RUNNABLE;

            me = _PR_MD_CURRENT_THREAD();

            _PR_AddThreadToRunQ(me, t);
            _PR_THREAD_UNLOCK(t);
        } else {
            t->state = _PR_RUNNING;
            _PR_THREAD_UNLOCK(t);
        }
        _PR_MD_WAKEUP_WAITER(t);
        break;
    }
    return;
}
static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
PRIntervalTime timeout)
{
	PROsfd osfd;
	PRFileDesc *fd2;
	PRUint32 al;
	PRThread *me = _PR_MD_CURRENT_THREAD();
#ifdef WINNT
	PRNetAddr addrCopy;
#endif

	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return 0;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return 0;
	}

#ifdef WINNT
	if (addr == NULL) {
		addr = &addrCopy;
	}
#endif
	al = sizeof(PRNetAddr);
	osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
	if (osfd == -1)
		return 0;

	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
	if (!fd2) {
		_PR_MD_CLOSE_SOCKET(osfd);
		return NULL;
	}

	fd2->secret->nonblocking = fd->secret->nonblocking;
	fd2->secret->inheritable = fd->secret->inheritable;
#ifdef WINNT
	if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
		/*
		 * The new socket has been associated with an I/O
		 * completion port.  There is no going back.
		 */
		fd2->secret->md.io_model_committed = PR_TRUE;
	}
	PR_ASSERT(al == PR_NETADDR_SIZE(addr));
	fd2->secret->md.accepted_socket = PR_TRUE;
	memcpy(&fd2->secret->md.peer_addr, addr, al);
#endif

	/*
	 * On some platforms, the new socket created by accept()
	 * inherits the nonblocking (or overlapped io) attribute
	 * of the listening socket.  As an optimization, these
	 * platforms can skip the following _PR_MD_MAKE_NONBLOCK
	 * call.
	 */
#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
	_PR_MD_MAKE_NONBLOCK(fd2);
#endif

#ifdef _PR_INET6
	if (addr && (AF_INET6 == addr->raw.family))
        addr->raw.family = PR_AF_INET6;
#endif
	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
	PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);

	return fd2;
}
Beispiel #29
0
/*
** Return the number of times that the current thread has entered the
** lock. Returns zero if the current thread has not entered the lock.
*/
PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
{
    return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ?
        mon->entryCount : 0;
}
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
PRIntervalTime timeout)
{
	PRInt32 rv;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	if ((flags != 0) && (flags != PR_MSG_PEEK)) {
		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
		return -1;
	}
	if (_PR_PENDING_INTERRUPT(me)) {
		me->flags &= ~_PR_INTERRUPT;
		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
		return -1;
	}
	if (_PR_IO_PENDING(me)) {
		PR_SetError(PR_IO_PENDING_ERROR, 0);
		return -1;
	}

	PR_LOG(_pr_io_lm, PR_LOG_MAX,
		("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d",
		fd, fd->secret->md.osfd, buf, amount, flags));

#ifdef _PR_HAVE_PEEK_BUFFER
	if (fd->secret->peekBytes != 0) {
		rv = (amount < fd->secret->peekBytes) ?
			amount : fd->secret->peekBytes;
		memcpy(buf, fd->secret->peekBuffer, rv);
		if (flags == 0) {
			/* consume the bytes in the peek buffer */
			fd->secret->peekBytes -= rv;
			if (fd->secret->peekBytes != 0) {
				memmove(fd->secret->peekBuffer,
					fd->secret->peekBuffer + rv,
					fd->secret->peekBytes);
			}
		}
		return rv;
	}

	/* allocate peek buffer, if necessary */
	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
		PR_ASSERT(0 == fd->secret->peekBytes);
		/* impose a max size on the peek buffer */
		if (amount > _PR_PEEK_BUFFER_MAX) {
			amount = _PR_PEEK_BUFFER_MAX;
		}
		if (fd->secret->peekBufSize < amount) {
			if (fd->secret->peekBuffer) {
				PR_Free(fd->secret->peekBuffer);
			}
			fd->secret->peekBufSize = amount;
			fd->secret->peekBuffer = PR_Malloc(amount);
			if (NULL == fd->secret->peekBuffer) {
				fd->secret->peekBufSize = 0;
				PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
				return -1;
			}
		}
	}
#endif

	rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
		rv, PR_GetError(), PR_GetOSError()));

#ifdef _PR_HAVE_PEEK_BUFFER
	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
		if (rv > 0) {
			memcpy(fd->secret->peekBuffer, buf, rv);
			fd->secret->peekBytes = rv;
		}
	}
#endif

	return rv;
}