void ScanAsyncFile::clean_slots() { pbuf.detach(); while( done_count ) { slots[done_ind].pbuf.detach(); done_ind=NextInd(done_ind); done_count--; } while( op_count ) { slots[op_ind].pbuf.detach(); op_ind=NextInd(op_ind); op_count--; } }
PtrLen<const char> ScanAsyncFile::underflow() { if( !is_opened ) { fail(); Printf(Exception,"CCore::ScanAsyncFile::underflow() : file is not opened"); return Nothing; } if( !remaining_len ) return Nothing; TimeScope time_scope(timeout); pump_read(time_scope); if( sem.take(time_scope) ) { Mutex::Lock lock(mutex); Slot *slot=slots+done_ind; done_ind=NextInd(done_ind); done_count--; free_count++; if( !slot->error ) { pbuf=std::move(slot->pbuf); remaining_len-=slot->len; return slot->getRange(); } } else { setError(FileError_ReadFault); } pset.cancel_and_wait(); fail(); Printf(Exception,"CCore::ScanAsyncFile::underflow() : #;",getError()); return Nothing; }
void ScanAsyncFile::complete(Slot *slot) { ulen ind=Dist(slots,slot); ulen delta=0; { Mutex::Lock lock(mutex); slot->done=true; if( ind==op_ind ) { while( op_count && slots[op_ind].done ) { op_ind=NextInd(op_ind); op_count--; done_count++; delta++; } } } sem.give_many(delta); }
static void *BeginNewThread(void *voidThread) { AValue *stack; AThread *t; AInstance *inst; void *threadData; athread_mutex_t *mutex; athread_cond_t *cond; /* NOTE: This code is fragile! Be careful when doing modifications because trivial changes in ordering of statements etc. may cause rare synchronization problems, especially with garbage collection. */ t = voidThread; athread_mutex_lock(&AThreadMutex); ADebugStatusMsg(("New os thread (%ld)\n", (long)t)); /* Each physical thread loops forever and waits for new arguments that signal the creation of a new Alore (logical) thread. */ for (;;) { ABool broadcast; /* FIX: perhaps gotta wake up something at some place.. no? */ /* Wait until we are given some arguments that indicate that we should start. The current thread is not active at this time, so NumThreads doesn't include it. Therefore don't call AAllowBlocking -- essentially the thread is always frozen. */ while (ArgBufFirst == ArgBufLast) athread_cond_wait(&ArgBufInsertCond, &AThreadMutex); /* From this point on, this thread is active. Keep track of the number of active threads. */ ANumThreads++; /* Initially all the threads could be frozen. Make sure that the thread is not frozen after we start the execution of the thread, since otherwise the garbage collector might be active. */ NumFreezableThreads++; DisallowFreezeNoLock(); /* This decrements NumFreezableThreads. */ /* If another thread may have read the arguments meanwhile, back off and try again. */ if (ArgBufFirst == ArgBufLast) { ANumThreads--; continue; } ADebugStatusMsg(("Alore thread started (%ld)\n", (long)t)); /* Construct a dummy stack frame at the bottom of the thread stack that stores information on the thread. */ stack = t->stackPtr - 7; /* The stack frame header is special, because it doesn't have a related Alore function. */ stack[0] = 7 * sizeof(AValue); /* IDEA: Use a macro? */ stack[1] = A_THREAD_BOTTOM_FUNCTION; stack[2] = A_COMPILED_FRAME_FLAG; /* FIX: Is this ok? */ /* Read the arguments given during Thread object creation and store them for future reference. */ stack[3] = AThreadArgBuffer[3 * ArgBufFirst + 0]; stack[4] = AThreadArgBuffer[3 * ArgBufFirst + 1]; stack[5] = AThreadArgBuffer[3 * ArgBufFirst + 2]; stack[6] = AZero; t->stackPtr = stack; /* Clear the arguments after they have been read to allow them to be reclaimed by the garbage collector. */ AThreadArgBuffer[3 * ArgBufFirst + 0] = AZero; AThreadArgBuffer[3 * ArgBufFirst + 1] = AZero; AThreadArgBuffer[3 * ArgBufFirst + 2] = AZero; /* Somebody might be waiting for a free slot in the argument buffer in order to create a new thread. Wake him up! */ if (ArgBufFirst == NextInd(ArgBufLast)) athread_cond_signal(&ArgBufRemoveCond); /* Mark a slot in the argument buffer as free. */ ArgBufFirst = NextInd(ArgBufFirst); athread_mutex_unlock(&AThreadMutex); /* The thread has been fully initialized. Now start the execution by calling the function given as an argument to the thread. Also catch any direct exceptions. */ if (AHandleException(t)) stack[4] = AError; else stack[4] = ACallValue(t, stack[4], 1 | A_VAR_ARG_FLAG, stack + 5); t->contextIndex--; inst = AValueToInstance(stack[3]); threadData = AValueToPtr(inst->member[A_THREAD_DATA]); mutex = GetThreadMutex(threadData); cond = GetThreadCond(threadData); athread_mutex_lock(mutex); broadcast = inst->member[A_THREAD_STATE] == AZero; inst->member[A_THREAD_STATE] = AIntToValue(1); if (AIsError(stack[4])) { inst->member[A_THREAD_STATE] = AIntToValue(2); stack[4] = t->exception; ACreateTracebackArray(t); /* FIX: is this ok..? */ inst = AValueToInstance(stack[3]); } if (!ASetInstanceMember(t, inst, A_THREAD_RET_VAL, stack + 4)) { inst = AValueToInstance(stack[3]); inst->member[A_THREAD_STATE] = AIntToValue(2); inst->member[A_THREAD_RET_VAL] = 0 /*MemoryErrorInstance*/; /* FIX!! */ } t->stackPtr = stack + 7; athread_mutex_lock(&AThreadMutex); NumWaitingThreads++; ANumThreads--; if (AIsFreeze && NumFreezableThreads == ANumThreads - 1) athread_cond_signal(&AllFrozenCond); ADebugStatusMsg(("Alore thread ended (%ld)\n", (long)t)); athread_mutex_unlock(mutex); if (broadcast) athread_cond_broadcast(cond); } /* Never reached */ /* Return a dummy NULL to get rid of a potential compiler warning. */ return NULL; }
AValue AThreadCreate(AThread *t, AValue *frame) { AThread *newThread; athread_t threadId; ABool isWaiting; AValue *threadData; /* Call the thread function always with no arguments. */ frame[2] = AMakeArray(t, 0); threadData = AAllocUnmovable(sizeof(AValue) + THREAD_DATA_SIZE); if (threadData == NULL) return ARaiseMemoryErrorND(t); AInitNonPointerBlockOld(threadData, THREAD_DATA_SIZE); *t->tempStack = ANonPointerBlockToValue(threadData); ASetMemberDirect(t, frame[0], A_THREAD_DATA, *t->tempStack); threadData = AValueToPtr(*t->tempStack); if (athread_mutex_init(GetThreadMutex(threadData), NULL) || athread_cond_init(GetThreadCond(threadData), NULL)) return ARaiseMemoryErrorND(t); athread_mutex_lock(&AThreadMutex); if (NumWaitingThreads > 0) { NumWaitingThreads--; isWaiting = TRUE; AAvoidWarning_M(newThread = NULL); } else { athread_mutex_unlock(&AThreadMutex); newThread = ACreateThread(frame + 3); if (newThread == NULL) return ARaiseMemoryErrorND(t); isWaiting = FALSE; athread_mutex_lock(&AThreadMutex); } /* Wait until the argument buffer is not full. */ while (ArgBufFirst == NextInd(ArgBufLast)) { AllowFreezeNoLock(); athread_cond_wait(&ArgBufRemoveCond, &AThreadMutex); DisallowFreezeNoLock(); } /* Store thread object, function to be executed and arguments. */ AThreadArgBuffer[3 * ArgBufLast ] = frame[0]; AThreadArgBuffer[3 * ArgBufLast + 1] = frame[1]; AThreadArgBuffer[3 * ArgBufLast + 2] = frame[2]; ArgBufLast = NextInd(ArgBufLast); athread_mutex_unlock(&AThreadMutex); if (isWaiting) athread_cond_signal(&ArgBufInsertCond); else { int result = athread_create(&threadId, BeginNewThread, newThread); if (result) return ARaiseMemoryErrorND(t); /* FIX: bad */ /* Perhaps store new thread id somewhere. */ } return frame[0]; }