/*! * \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); }
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; }
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; }
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; }
/*! * \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; }
/*! * \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); }
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); }
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); }
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; }
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; }
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); } } }
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); }
/*! * \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); }
/* * 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); }
/* ------------------------ * 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; }
/* * 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); }
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; }