void TempoClock::Add(double inBeats, PyrSlot* inTask) { double prevBeats = mQueue->size > 1 ? slotRawFloat(mQueue->slots) : -1e10; bool added = addheap(g, (PyrObject*)mQueue, inBeats, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inBeats); } if (slotRawFloat(mQueue->slots) != prevBeats) { pthread_cond_signal (&mCondition); } } }
void dumpheap(PyrObject *heapArg) { PyrHeap * heap = (PyrHeap*)heapArg; double mintime = slotRawFloat(&heap->slots[0]); int count = slotRawFloat(&heap->slots[2]); int heapSize = heap->size - 1; post("SCHED QUEUE (%d)\n", heapSize); for (int i=0; i<heapSize; i+=3) { post("%3d(%3d) %9.2f %p %d\n", i/3, i, slotRawFloat(&heap->slots[i]), slotRawObject(&heap->slots[i+1]), slotRawInt(&heap->slots[i+2])); if ((slotRawFloat(&heap->slots[i]) < mintime) || (slotRawFloat(&heap->slots[i]) == mintime && slotRawInt(&heap->slots[i+2]) < count ) ) post("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } }
void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask) { // gLangMutex must be locked double prevTime = inQueue->size > 1 ? slotRawFloat(inQueue->slots + 1) : -1e10; bool added = addheap(g, inQueue, inSeconds, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inSeconds); } if (slotRawFloat(inQueue->slots + 1) != prevTime) { //post("pthread_cond_signal\n"); pthread_cond_signal (&gSchedCond); } } }
void offsetheap(VMGlobals *g, PyrObject *heap, double offset) { long i; for (i=0; i<heap->size; i+=2) { SetRaw(&heap->slots[i], slotRawFloat(&heap->slots[i]) + offset); //post("%3d %9.2f %9.2f\n", i>>1, heap->slots[i].uf, offset); } }
bool lookheap(PyrObject *heap, double *schedtime, PyrSlot *task) { if (heap->size > 1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); return true; } else return false; }
inline int prOpFloat(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawFloat(a), (double)slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawFloat(a), slotRawObject(b))); else goto send_normal_2; break; default : SetRaw(a, Functor::run(slotRawFloat(a), slotRawFloat(b))); break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; }
int prAs32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; // return an integer that is a bit pattern for the 32 bit float representation union { float f; int32 i; } u; u.f = slotRawFloat(a); SetInt(a, u.i); return errNone; }
static int addMsgSlot(big_scpacket *packet, PyrSlot *slot) { switch (GetTag(slot)) { case tagInt : packet->addi(slotRawInt(slot)); break; case tagSym : packet->adds(slotRawSymbol(slot)->name); break; case tagObj : if (isKindOf(slotRawObject(slot), class_string)) { PyrString *stringObj = slotRawString(slot); packet->adds(stringObj->s, stringObj->size); } else if (isKindOf(slotRawObject(slot), class_int8array)) { PyrInt8Array *arrayObj = slotRawInt8Array(slot); packet->addb(arrayObj->b, arrayObj->size); } else if (isKindOf(slotRawObject(slot), class_array)) { PyrObject *arrayObj = slotRawObject(slot); big_scpacket packet2; if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) { makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true); } else { int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size); if (error != errNone) return error; } packet->addb((uint8*)packet2.data(), packet2.size()); } break; case tagNil : case tagTrue : case tagFalse : case tagChar : case tagPtr : break; default : if (gUseDoubles) packet->addd(slotRawFloat(slot)); else packet->addf(slotRawFloat(slot)); break; } return errNone; }
void PriorityQueuePostpone(PyrObject* queueobj, double time) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); PyrSlot* slots = schedq->slots; for (int i=1; i < schedq->size; i+=3) { SetRaw(&slots[i], slotRawFloat(&slots[i]) + time); } } }
int prLow32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.f = slotRawFloat(a); SetInt(a, du.i.lo); return errNone; }
bool addheap(VMGlobals *g, PyrObject *heapArg, double schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif if (heap->size >= ARRAYMAXINDEXSIZE(heap)) return false; assert(heap->size); // post("->addheap\n"); // dumpheap(heapArg); /* parent and sibling in the heap, not in the task hierarchy */ int mom = heap->size - 1; PyrSlot * pme = heap->slots + mom; int stabilityCount = slotRawInt(&heap->count); SetRaw(&heap->count, stabilityCount + 1); for (; mom>0;) { /* percolate up heap */ int newMom = ((mom - 3) / 2); mom = newMom - newMom % 3; /// LATER: we could avoid the division by using 4 slots per element PyrSlot * pmom = heap->slots + mom; if (schedtime < slotRawFloat(pmom)) { assert(slotRawInt(pmom + 2) < stabilityCount); slotCopy(&pme[0], &pmom[0]); slotCopy(&pme[1], &pmom[1]); slotCopy(&pme[2], &pmom[2]); pme = pmom; } else break; } SetFloat(&pme[0], schedtime); slotCopy(&pme[1], task); SetInt(&pme[2], stabilityCount); g->gc->GCWrite(heap, task); heap->size += 3; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // dumpheap(heapArg); // post("<-addheap %g\n", schedtime); return true; }
int prNetAddr_SendBundle(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1; PyrSlot* args = netAddrSlot + 1; big_scpacket packet; double time; int err = slotDoubleVal(args, &time); if (!err) { time += slotRawFloat(&g->thread->seconds); SetFloat(args, time); } int numargs = numArgsPushed - 1; makeSynthBundle(&packet, args, numargs, true); //for (int i=0; i<packet.size()/4; i++) post("%d %p\n", i, packet.buf[i]); return netAddrSend(slotRawObject(netAddrSlot), packet.size(), (char*)packet.buf); }
int mathFoldFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_fold(slotRawFloat(a), lo, hi)); } return errNone; }
void serialize(PyrSlot * slot) { if (IsFloat(slot)) { emitter << slotRawFloat(slot); return; } switch (GetTag(slot)) { case tagNil: emitter << YAML::Null; return; case tagInt: emitter << slotRawInt(slot); return; case tagFalse: emitter << false; return; case tagTrue: emitter << true; return; case tagObj: serialize(slotRawObject(slot)); return; case tagSym: emitter << YAML::DoubleQuoted << slotRawSymbol(slot)->name; return; default: printf ("type: %d\n", GetTag(slot)); throw std::runtime_error("YAMLSerializer: not implementation for this type"); } }
int prFileWriteLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *ptr; PyrFile *pfile; FILE *file; PyrObject *obj; char chr; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; switch (GetTag(b)) { case tagInt : { SC_IOStream<FILE*> scio(file); scio.writeInt32_le(slotRawInt(b)); break; } case tagSym : fwrite(slotRawSymbol(b)->name, sizeof(char), slotRawSymbol(b)->length, file); break; case tagChar : chr = slotRawInt(b); fwrite(&chr, sizeof(char), 1, file); break; case tagNil : case tagFalse : case tagTrue : case tagPtr : return errWrongType; case tagObj : { // writes the indexable part of any non obj_slot format object obj = slotRawObject(b); if (!isKindOf(obj, class_rawarray) || isKindOf(obj, class_symbolarray)) return errWrongType; if (obj->size) { ptr = obj->slots; int elemSize = gFormatElemSize[obj->obj_format]; int numElems = obj->size; #if BYTE_ORDER == BIG_ENDIAN switch (elemSize) { case 1: fwrite(ptr, elemSize, numElems, file); break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { fputc(ptr[7], file); fputc(ptr[6], file); fputc(ptr[5], file); fputc(ptr[4], file); fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } } #else fwrite(ptr, elemSize, numElems, file); #endif } break; } default : // double { SC_IOStream<FILE*> scio(file); scio.writeDouble_le(slotRawFloat(b)); break; } } return errNone; }
static float read( PyrSlot *slot ) { return slotRawFloat(slot); }
bool getheap(VMGlobals *g, PyrObject *heapArg, double *schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; PyrGC* gc = g->gc; bool isPartialScanObj = gc->IsPartialScanObject(heapArg); assert(heap->size); // post("->getheap\n"); // dumpheap(heapArg); if (heap->size>1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); heap->size -= 3; int size = heap->size - 1; slotCopy(&heap->slots[0], &heap->slots[size]); slotCopy(&heap->slots[1], &heap->slots[size+1]); slotCopy(&heap->slots[2], &heap->slots[size+2]); /* parent and sibling in the heap, not in the task hierarchy */ int mom = 0; int me = 3; PyrSlot * pmom = heap->slots + mom; PyrSlot * pme = heap->slots + me; PyrSlot * pend = heap->slots + size; double timetemp = slotRawFloat(&pmom[0]); int stabilityCountTemp = slotRawInt(&pmom[2]); PyrSlot tasktemp; slotCopy(&tasktemp, &pmom[1]); for (;pme < pend;) { /* demote heap */ if (pme+3 < pend && ((slotRawFloat(&pme[0]) > slotRawFloat(&pme[3])) || ((slotRawFloat(&pme[0]) == slotRawFloat(&pme[3])) && (slotRawInt(&pme[2]) > slotRawInt(&pme[5])) ))) { me += 3; pme += 3; } if (timetemp > slotRawFloat(&pme[0]) || (timetemp == slotRawFloat(&pme[0]) && stabilityCountTemp > slotRawInt(&pme[2]))) { slotCopy(&pmom[0], &pme[0]); slotCopy(&pmom[1], &pme[1]); slotCopy(&pmom[2], &pme[2]); if (isPartialScanObj) { gc->GCWriteBlack(pmom+1); } pmom = pme; me = ((mom = me) * 2) + 3; pme = heap->slots + me; } else break; } SetRaw(&pmom[0], timetemp); slotCopy(&pmom[1], &tasktemp); SetRaw(&pmom[2], stabilityCountTemp); if (isPartialScanObj) gc->GCWriteBlack(pmom+1); if (size == 0) SetInt(&heap->count, 0); // dumpheap(heapArg); // post("<-getheap true\n"); return true; } else { // post("<-getheap false\n"); return false; } }
void* TempoClock::Run() { //printf("->TempoClock::Run\n"); pthread_mutex_lock (&gLangMutex); while (mRun) { assert(mQueue->size); //printf("tempo %g dur %g beats %g\n", mTempo, mBeatDur, mBeats); //printf("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (mQueue->size == 1) { //printf("wait until there is something in scheduler\n"); pthread_cond_wait (&mCondition, &gLangMutex); //printf("mRun a %d\n", mRun); if (!mRun) goto leave; } //printf("wait until an event is ready\n"); // wait until an event is ready double elapsedBeats; do { elapsedBeats = ElapsedBeats(); if (elapsedBeats >= slotRawFloat(mQueue->slots)) break; struct timespec abstime; //doubleToTimespec(mQueue->slots->uf, &abstime); //printf("event ready at %g . elapsed beats %g\n", mQueue->slots->uf, elapsedBeats); double wakeTime = BeatsToSecs(slotRawFloat(mQueue->slots)); ElapsedTimeToTimespec(wakeTime, &abstime); //printf("wait until an event is ready. wake %g now %g\n", wakeTime, elapsedTime()); pthread_cond_timedwait (&mCondition, &gLangMutex, &abstime); //printf("mRun b %d\n", mRun); if (!mRun) goto leave; //printf("time diff %g\n", elapsedTime() - mQueue->slots->uf); } while (mQueue->size > 1); //printf("perform all events that are ready %d %.9f\n", mQueue->size, elapsedBeats); // perform all events that are ready //printf("perform all events that are ready\n"); while (mQueue->size > 1 && elapsedBeats >= slotRawFloat(mQueue->slots)) { double delta; PyrSlot task; //printf("while %.6f >= %.6f\n", elapsedBeats, mQueue->slots->uf); getheap(g, (PyrObject*)mQueue, &mBeats, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, mBeats); SetFloat(++g->sp, BeatsToSecs(mBeats)); ++g->sp; SetObject(g->sp, mTempoClockObj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double beats = mBeats + delta; Add(beats, &task); } } } leave: //printf("<-TempoClock::Run\n"); pthread_mutex_unlock (&gLangMutex); return 0; }
void* schedRunFunc(void* arg) { pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); //dumpObject(inQueue); gRunSched = true; while (true) { assert(inQueue->size); //postfl("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (inQueue->size == 1) { //postfl("wait until there is something in scheduler\n"); pthread_cond_wait (&gSchedCond, &gLangMutex); if (!gRunSched) goto leave; } //postfl("wait until an event is ready\n"); // wait until an event is ready double elapsed; do { elapsed = elapsedTime(); if (elapsed >= slotRawFloat(inQueue->slots + 1)) break; struct timespec abstime; //doubleToTimespec(inQueue->slots->uf, &abstime); ElapsedTimeToTimespec(slotRawFloat(inQueue->slots + 1), &abstime); //postfl("wait until an event is ready\n"); pthread_cond_timedwait (&gSchedCond, &gLangMutex, &abstime); if (!gRunSched) goto leave; //postfl("time diff %g\n", elapsedTime() - inQueue->slots->uf); } while (inQueue->size > 1); //postfl("perform all events that are ready %d %.9f\n", inQueue->size, elapsed); // perform all events that are ready //postfl("perform all events that are ready\n"); while ((inQueue->size > 1) && elapsed >= slotRawFloat(inQueue->slots + 1)) { double schedtime, delta; PyrSlot task; //postfl("while %.6f >= %.6f\n", elapsed, inQueue->slots->uf); getheap(g, inQueue, &schedtime, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, schedtime); SetFloat(++g->sp, schedtime); ++g->sp; SetObject(g->sp, s_systemclock->u.classobj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double time = schedtime + delta; schedAdd(g, inQueue, time, &task); } } //postfl("loop\n"); } //postfl("exitloop\n"); leave: pthread_mutex_unlock (&gLangMutex); return 0; }