Beispiel #1
0
/*!
 *  \brief  Removes a thread from a thread queue
 */
void ThrRemoveQueue(thread_t *thr, thread_queue_t *queue)
{
    thread_queuent_t *ent;

    SpinAcquire(&sc_sem);
    ent = ThrFindInQueue(queue, thr);
    if (ent == NULL)
    {
        SpinRelease(&sc_sem);
        return;
    }

    if (ent->prev)
        ent->prev->next = ent->next;
    if (ent->next)
        ent->next->prev = ent->prev;
    if (queue->first == ent)
        queue->first = ent->next;
    if (queue->last == ent)
        queue->last = ent->prev;

    SlabFree(&slab_thread_queuent, ent);
    KeAtomicDec(&thr->queued);
    TRACE2("ThrRemoveQueue: thread %u removed from queue %p\n",
        thr->id, queue);

    SpinRelease(&sc_sem);
}
Beispiel #2
0
bool PortPassthrough(fsd_t *fsd, file_t *file, uint32_t code, void *buf, 
                     size_t length, fs_asyncio_t *io)
{
    params_port_t *params;
    port_t *server;

    params = buf;

    if (length < sizeof(params_port_t))
    {
        io->op.result = EBUFFER;
        return false;
    }

    server = file->fsd_cookie;
    if (!server->is_server)
    {
        io->op.result = EACCESS;
        return false;
    }

    switch (code)
    {
    case PORT_LISTEN:
    case PORT_CONNECT:
        //wprintf(L"PortPassthrough(%p): PORT_LISTEN and PORT_CONNECT not implemented\n",
            //server);
        //FsNotifyCompletion(io, length, 0);
        //break;
        io->op.result = ENOTIMPL;
        return false;

    case PORT_ACCEPT:
        SpinAcquire(&server->u.server.sem);
        if (server->u.server.io_listen != NULL)
        {
            SpinRelease(&server->u.server.sem);
            io->op.result = EACCESS;
            return false;
        }

        //wprintf(L"PortPassthrough(%p): PORT_ACCEPT, waiter = %p\n",
            //server,
            //server->u.server.waiter_first);
        server->u.server.io_listen = io;
        server->u.server.pages_listen = MemCreatePageArray(buf, length);
        SpinRelease(&server->u.server.sem);
        io->op.result = io->original->result = SIOPENDING;
        PortWakeBlockedAcceptors(server);
        break;

    default:
        io->op.result = ENOTIMPL;
        return false;
    }

    return true;
}
Beispiel #3
0
status_t PortCreateFile(fsd_t *fsd, vnode_id_t dir, const wchar_t *name, 
                        void **cookie)
{
    port_fsd_t *pfsd;
    port_t *server;

    pfsd = (port_fsd_t*) fsd;
    assert(dir == VNODE_ROOT);

    //wprintf(L"PortCreateFile(%s)\n", name);

    server = malloc(sizeof(port_t));
    if (server == NULL)
        return errno;

    memset(server, 0, sizeof(port_t));
    server->is_server = true;
    server->u.server.name = _wcsdup(name);
    *cookie = server;

    SpinAcquire(&pfsd->sem);
    LIST_ADD(pfsd->server, server);
    SpinRelease(&pfsd->sem);

    return 0;
}
Beispiel #4
0
bool RtlIsr(device_t *device, uint8_t irq)
{
    rtl8139_t *rtl;
    uint16_t status;

    rtl = device->cookie;

    SpinAcquire(&rtl->sem);
    out16(rtl->iobase + IntrMask, 0);

    status = in16(rtl->iobase + IntrStatus);
    out16(rtl->iobase + IntrStatus, status & ~(RxFIFOOver | RxOverflow | RxOK));

    if (status & (RxOK | RxErr))
        RtlHandleRx(rtl);
    else if (status & TxOK)
        RtlHandleTx(rtl);
    else
        wprintf(L"rtl8139: unknown interrupt: isr = %04x\n", status);

    out16(rtl->iobase + IntrStatus, status & (RxFIFOOver | RxOverflow | RxOK));
    out16(rtl->iobase + IntrMask, IntrDefault);
    SpinRelease(&rtl->sem);

    return true;
}
Beispiel #5
0
/*!
 *  \brief  Places the specified thread onto the run queue for the 
 *      appropriate priority
 */
static bool ThrRun(thread_t *thr)
{
    assert(thr->priority < _countof(thr_priority));

    ThrInsertQueue(thr, thr_priority + thr->priority, NULL);
    SpinAcquire(&sc_sem);
    thr_queue_ready |= 1 << thr->priority;
    SpinRelease(&sc_sem);
    return true;
}
Beispiel #6
0
/*!
 *    \brief        Runs a queue of threads
 *
 *    The threads on the queue are removed from the queue and added to their 
 *    respective priority queues, to be scheduled next time the scheduler is 
 *    called.
 *
 *    \param        queue         Queue to run
 */
static void ThrRunQueue(thread_queue_t *queue)
{
    thread_queuent_t *ent, *next;
    thread_t *thr;

    SpinAcquire(&sc_sem);
    while (queue->first != NULL)
    {
        ent = queue->first;
        next = ent->next;
        thr = ent->thr;
        TRACE1("ThrRunQueue: running thread %u\n", thr->id);
        SpinRelease(&sc_sem);
        ThrRemoveQueue(thr, queue);
        ThrRun(thr);
        SpinAcquire(&sc_sem);
    }

    ScNeedSchedule(true);
    SpinRelease(&sc_sem);
}
Beispiel #7
0
void RtlInit(rtl8139_t *rtl)
{
    unsigned i;

    wprintf(L"rtl8139: resetting... ");

    SpinAcquire(&rtl->sem);

    /* Bring the chip out of low-power mode. */
    out(rtl->iobase + Config1, 0x00);

    if (RtlReadEeprom(rtl, 0) != 0xffff)
    {
        unsigned short *ap = (unsigned short*)rtl->station_address;
        for (i = 0; i < 3; i++)
            *ap++ = RtlReadEeprom(rtl, i + 7);
    }
    else
    {
        unsigned char *ap = (unsigned char*)rtl->station_address;
        for (i = 0; i < 6; i++)
            *ap++ = in(rtl->iobase + MAC0 + i);
    }

    rtl->speed10 = (in(rtl->iobase + MediaStatus) & MSRSpeed10) != 0;
    rtl->fullduplex = (in16(rtl->iobase + MII_BMCR) & BMCRDuplex) != 0;
    wprintf(L"rtl8139: %sMbps %s-duplex\n", 
        rtl->speed10 ? L"10" : L"100",
        rtl->fullduplex ? L"full" : L"half");

    rtl->rx_phys = MemAlloc();
    rtl->tx_phys = MemAlloc();

    rtl->rx_ring = sbrk_virtual(RX_BUF_LEN);
    rtl->tx_ring = sbrk_virtual(TX_BUF_SIZE);

    wprintf(L"rtl8139: rx_ring = %p, tx_ring = %p\n",
        rtl->rx_ring, rtl->tx_ring);

    MemMapRange(rtl->rx_ring, 
        rtl->rx_phys, 
        rtl->rx_ring + RX_BUF_LEN,
        PRIV_RD | PRIV_PRES | PRIV_KERN);
    MemMapRange(rtl->tx_ring, 
        rtl->tx_phys, 
        (uint8_t*) PAGE_ALIGN_UP((addr_t) rtl->tx_ring + TX_BUF_SIZE),
        PRIV_WR | PRIV_PRES | PRIV_KERN);

    RtlReset(rtl);
    SpinRelease(&rtl->sem);
}
Beispiel #8
0
static void PortWakeBlockedAcceptors(port_t *server)
{
    params_port_t *params;
    fs_asyncio_t *io;
    port_waiter_t *waiter;

    assert(server->is_server);
    SpinAcquire(&server->u.server.sem);
    io = server->u.server.io_listen;
    waiter = server->u.server.waiter_first;
    //wprintf(L"PortWakeBlockedAcceptors(%p): io = %p, waiter = %p\n",
        //server, io, waiter);

    if (io != NULL && waiter != NULL)
    {
        file_t *file;
        file_handle_t *fh;

        params = MemMapPageArray(server->u.server.pages_listen);
        file = FsCreateFileObject(&pipe_fsd, VNODE_NONE, waiter->end_server);
        fh = FsCreateFileHandle(file, params->port_accept.flags);
        params->port_accept.client = HndDuplicate(&fh->hdr, io->owner->process);
            
        //wprintf(L"PortWakeBlockedAcceptors(%p): pipe = %p, handle = %u\n",
            //server, waiter->end_server, params->port_accept.client);
        MemUnmapPageArray(server->u.server.pages_listen);

        LIST_REMOVE(server->u.server.waiter, waiter);
        free(waiter);
        MemDeletePageArray(server->u.server.pages_listen);
        server->u.server.io_listen = NULL;
        server->u.server.pages_listen = NULL;
        SpinRelease(&server->u.server.sem);
        FsNotifyCompletion(io, sizeof(params_port_t), 0);
    }
    else
        SpinRelease(&server->u.server.sem);
}
Beispiel #9
0
status_t PortParseElement(fsd_t *fsd, const wchar_t *name, 
                          wchar_t **new_path, vnode_t *node)
{
    port_fsd_t *pfsd;
    port_t *server;

    pfsd = (port_fsd_t*) fsd;
    assert(node->id == VNODE_ROOT);

    SpinAcquire(&pfsd->sem);
    for (server = pfsd->server_first; server != NULL; server = server->next)
    {
        assert(server->is_server);
        if (_wcsicmp(server->u.server.name, name) == 0)
        {
            node->id = (vnode_id_t) server;
            SpinRelease(&pfsd->sem);
            return 0;
        }
    }

    SpinRelease(&pfsd->sem);
    return ENOTFOUND;
}
Beispiel #10
0
status_t PortLookupFile(fsd_t *fsd, vnode_id_t node, uint32_t open_flags, 
                        void **cookie)
{
    port_fsd_t *pfsd;
    port_t *server, *client;
    port_waiter_t *waiter;
    pipe_t *ends[2];

    pfsd = (port_fsd_t*) fsd;
    if (node == VNODE_ROOT)
        return EACCESS;

    server = (port_t*) node;
    assert(server->is_server);

    client = malloc(sizeof(port_t));
    if (client == NULL)
        goto error0;

    waiter = malloc(sizeof(port_waiter_t));
    if (waiter == NULL)
        goto error1;

    if (!FsCreatePipeInternal(ends))
        goto error2;

    memset(client, 0, sizeof(*client));
    memset(waiter, 0, sizeof(*waiter));
    client->is_server = false;
    waiter->end_client = client->u.client = ends[0];
    waiter->end_server = ends[1];

    SpinAcquire(&server->u.server.sem);
    LIST_ADD(server->u.server.waiter, waiter);
    SpinRelease(&server->u.server.sem);

    *cookie = client;
    PortWakeBlockedAcceptors(server);
    return 0;

error2:
    free(waiter);
error1:
    free(client);
error0:
    return errno;
}
Beispiel #11
0
void
ProcReleaseSpins(PROC *proc)
{
    int i;
    
    if (!proc)
	proc = MyProc;
    
    if (!proc)
	return;
    for (i=0; i < (int)MAX_SPINS; i++)
	{
	    if (proc->sLocks[i])
		{
		    Assert(proc->sLocks[i] == 1);
		    SpinRelease(i);
		}
	}
}
Beispiel #12
0
void PortFreeCookie(fsd_t *fsd, void *cookie)
{
    port_fsd_t *pfsd;
    port_t *server;

    pfsd = (port_fsd_t*) fsd;
    server = cookie;

    if (server->is_server)
    {
        SpinAcquire(&pfsd->sem);
        LIST_REMOVE(pfsd->server, server);
        SpinRelease(&pfsd->sem);

        free(server->u.server.name);
    }
    else
        PipeFreeCookie(fsd, server->u.client);

    free(server);
}
Beispiel #13
0
/*!
 *  \brief  Inserts a thread into a thread queue
 */
static void ThrInsertQueue(thread_t *thr, thread_queue_t *queue, thread_queuent_t *before)
{
    thread_queuent_t *ent;

    SpinAcquire(&sc_sem);
    ent = SlabAlloc(&slab_thread_queuent);
    assert(ent != NULL);
    ent->thr = thr;

    if (before == NULL)
    {
        if (queue->last != NULL)
            queue->last->next = ent;

        ent->prev = queue->last;
        ent->next = NULL;
        queue->last = ent;

        if (queue->first == NULL)
            queue->first = ent;
    }
    else
    {
        ent->next = before;
        ent->prev = before->prev;
        if (before->prev != NULL)
            before->prev->next = ent;
        before->prev = ent;
        if (queue->first == before)
            queue->first = ent;
    }

    KeAtomicInc(&thr->queued);
    TRACE2("ThrInsertQueue: thread %u added to queue %p\n",
        thr->id, queue);

    SpinRelease(&sc_sem);
}
Beispiel #14
0
/*
 * ProcRemove -
 *    used by the postmaster to clean up the global tables. This also frees
 *    up the semaphore used for the lmgr of the process. (We have to do
 *    this is the postmaster instead of doing a IpcSemaphoreKill on exiting
 *    the process because the semaphore set is shared among backends and
 *    we don't want to remove other's semaphores on exit.)
 */
bool
ProcRemove(int pid)
{
    SHMEM_OFFSET  location;
    PROC *proc;
    
    location = INVALID_OFFSET;
    
    location = ShmemPIDDestroy(pid);
    if (location == INVALID_OFFSET)
	return(FALSE);
    proc = (PROC *) MAKE_PTR(location);

    SpinAcquire(ProcStructLock);
    
    ProcFreeSem(proc->sem.semKey, proc->sem.semNum);

    proc->links.next =  ProcGlobal->freeProcs;
    ProcGlobal->freeProcs = MAKE_OFFSET(proc);
    
    SpinRelease(ProcStructLock);

    return(TRUE);
}
Beispiel #15
0
/* ------------------------
 * InitProc -- create a per-process data structure for this process
 * used by the lock manager on semaphore queues.
 * ------------------------
 */
void
InitProcess(IPCKey key)
{
    bool found = false;
    int pid;
    int semstat;
    unsigned long location, myOffset;
    
    /* ------------------
     * Routine called if deadlock timer goes off. See ProcSleep()
     * ------------------
     */
#ifndef WIN32
    signal(SIGALRM, HandleDeadLock);
#endif /* WIN32 we'll have to figure out how to handle this later */

    SpinAcquire(ProcStructLock);
    
    /* attach to the free list */
    ProcGlobal = (PROC_HDR *)
	ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
    if (!found) {
	/* this should not happen. InitProcGlobal() is called before this. */
	elog(WARN, "InitProcess: Proc Header uninitialized");
    }
    
    if (MyProc != NULL)
	{
	    SpinRelease(ProcStructLock);
	    elog(WARN,"ProcInit: you already exist");
	    return;
	}
    
    /* try to get a proc from the free list first */
    
    myOffset = ProcGlobal->freeProcs;
    
    if (myOffset != INVALID_OFFSET)
	{
	    MyProc = (PROC *) MAKE_PTR(myOffset);
	    ProcGlobal->freeProcs = MyProc->links.next;
	}
    else
	{
	    /* have to allocate one.  We can't use the normal binding
	     * table mechanism because the proc structure is stored
	     * by PID instead of by a global name (need to look it
	     * up by PID when we cleanup dead processes).
	     */
	    
	    MyProc = (PROC *) ShmemAlloc((unsigned)sizeof(PROC));
	    if (! MyProc)
		{
		    SpinRelease(ProcStructLock);
		    elog (FATAL,"cannot create new proc: out of memory");
		}
	    
	    /* this cannot be initialized until after the buffer pool */
	    SHMQueueInit(&(MyProc->lockQueue));
	    MyProc->procId = ProcGlobal->numProcs;
	    ProcGlobal->numProcs++;
	}
    
    /*
     * zero out the spin lock counts and set the sLocks field for
     * ProcStructLock to 1 as we have acquired this spinlock above but 
     * didn't record it since we didn't have MyProc until now.
     */
    memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
    MyProc->sLocks[ProcStructLock] = 1;


    if (IsUnderPostmaster) {
	IPCKey semKey;
	int semNum;
	int semId;
	union semun semun;

	ProcGetNewSemKeyAndNum(&semKey, &semNum);
	
	semId = IpcSemaphoreCreate(semKey,
				   PROC_NSEMS_PER_SET,
				   IPCProtection,
				   IpcSemaphoreDefaultStartValue,
				   0,
				   &semstat);
	/*
	 * we might be reusing a semaphore that belongs to a dead
	 * backend. So be careful and reinitialize its value here.
	 */
	semun.val = IpcSemaphoreDefaultStartValue;
	semctl(semId, semNum, SETVAL, semun);

	IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
	MyProc->sem.semId = semId;
	MyProc->sem.semNum = semNum;
	MyProc->sem.semKey = semKey;
    } else {
	MyProc->sem.semId = -1;
    }
    
    /* ----------------------
     * Release the lock.
     * ----------------------
     */
    SpinRelease(ProcStructLock);
    
    MyProc->pid = 0;
#if 0
    MyProc->pid = MyPid;
#endif
    
    /* ----------------
     * Start keeping spin lock stats from here on.  Any botch before
     * this initialization is forever botched
     * ----------------
     */
    memset(MyProc->sLocks, 0, MAX_SPINS*sizeof(*MyProc->sLocks));
    
    /* -------------------------
     * Install ourselves in the binding table.  The name to
     * use is determined by the OS-assigned process id.  That
     * allows the cleanup process to find us after any untimely
     * exit.
     * -------------------------
     */
    pid = getpid();
    location = MAKE_OFFSET(MyProc);
    if ((! ShmemPIDLookup(pid,&location)) || (location != MAKE_OFFSET(MyProc)))
	{
	    elog(FATAL,"InitProc: ShmemPID table broken");
	}
    
    MyProc->errType = NO_ERROR;
    SHMQueueElemInit(&(MyProc->links));
    
    on_exitpg(ProcKill, (caddr_t)pid);
    
    ProcInitialized = TRUE;
}
Beispiel #16
0
/*
 * ProcSleep -- put a process to sleep
 *
 * P() on the semaphore should put us to sleep.  The process
 * semaphore is cleared by default, so the first time we try
 * to acquire it, we sleep.
 *
 * ASSUME: that no one will fiddle with the queue until after
 * 	we release the spin lock.
 *
 * NOTES: The process queue is now a priority queue for locking.
 */
int
ProcSleep(PROC_QUEUE *queue,
	  SPINLOCK spinlock,
	  int token,
	  int prio,
	  LOCK *lock)
{
    int 	i;
    PROC	*proc;
#ifndef WIN32 /* figure this out later */
    struct itimerval timeval, dummy;
#endif /* WIN32 */
    
    proc = (PROC *) MAKE_PTR(queue->links.prev);
    for (i=0;i<queue->size;i++)
	{
	    if (proc->prio < prio)
		proc = (PROC *) MAKE_PTR(proc->links.prev);
	    else
		break;
	}
    
    MyProc->token = token;
    MyProc->waitLock = lock;
    
    /* -------------------
     * currently, we only need this for the ProcWakeup routines
     * -------------------
     */
    TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
    
    /* -------------------
     * assume that these two operations are atomic (because
     * of the spinlock).
     * -------------------
     */
    SHMQueueInsertTL(&(proc->links),&(MyProc->links));
    queue->size++;
    
    SpinRelease(spinlock);
    
    /* --------------
     * Postgres does not have any deadlock detection code and for this 
     * reason we must set a timer to wake up the process in the event of
     * a deadlock.  For now the timer is set for 1 minute and we assume that
     * any process which sleeps for this amount of time is deadlocked and will 
     * receive a SIGALRM signal.  The handler should release the processes
     * semaphore and abort the current transaction.
     *
     * Need to zero out struct to set the interval and the micro seconds fields
     * to 0.
     * --------------
     */
#ifndef WIN32
    memset(&timeval, 0, sizeof(struct itimerval));
    timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
    
    if (setitimer(ITIMER_REAL, &timeval, &dummy))
	elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
#endif /* WIN32 */
    
    /* --------------
     * if someone wakes us between SpinRelease and IpcSemaphoreLock,
     * IpcSemaphoreLock will not block.  The wakeup is "saved" by
     * the semaphore implementation.
     * --------------
     */
    IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
    
    /* ---------------
     * We were awoken before a timeout - now disable the timer
     * ---------------
     */
#ifndef WIN32
    timeval.it_value.tv_sec = 0;
    
    
    if (setitimer(ITIMER_REAL, &timeval, &dummy))
	elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
#endif /* WIN32 */
    
    /* ----------------
     * We were assumed to be in a critical section when we went
     * to sleep.
     * ----------------
     */
    SpinAcquire(spinlock);
    
    return(MyProc->errType);
}
Beispiel #17
0
static status_t RtlRequest(device_t *device, request_t* req)
{
    rtl8139_t *rtl;
    request_eth_t *req_eth;
    request_net_t *req_net;
    asyncio_t *io;
    bool was_empty;
    net_hwaddr_t *addr;

    rtl = device->cookie;
    req_eth = (request_eth_t*) req;
    req_net = (request_net_t*) req;
    switch (req->code)
    {
    case ETH_SEND:
    case ETH_RECEIVE:
        if (req->code == ETH_SEND)
        {
            was_empty = true;
            for (io = device->io_first; io != NULL; io = io->next)
                if (io->req->code == ETH_SEND)
                    was_empty = false;
        }
        else
            was_empty = true;

        io = DevQueueRequest(device, 
            &req_eth->header, 
            sizeof(*req_eth),
            req_eth->params.buffered.pages,
            req_eth->params.buffered.length);

        if (io == NULL)
        {
            req->result = errno;
            return false;
        }

        io->extra = NULL;
        if (was_empty)
        {
            SpinAcquire(&rtl->sem);
            RtlStartIo(rtl);
            SpinRelease(&rtl->sem);
        }

        return true;

    case NET_GET_HW_INFO:
        addr = req_net->params.net_hw_info.addr;
        if (addr != NULL)
        {
            if (req_net->params.net_hw_info.addr_data_size < 6)
            {
                req->result = EBUFFER;
                req_net->params.net_hw_info.addr_data_size = 6;
                return false;
            }

            memcpy(addr->u.ethernet, rtl->station_address, 6);
            addr->type = NET_HW_ETHERNET;
            addr->data_size = 6;
        }

        req_net->params.net_hw_info.addr_data_size = 6;
        req_net->params.net_hw_info.mtu = ETH_MAX_MTU;
        return true;
    }

    req->result = ENOTIMPL;
    return false;
}