int LbqPollQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) { PLINKED_BLOCKING_QUEUE_ENTRY entry; if (queueHead->head == NULL) { return LBQ_NO_ELEMENT; } PltLockMutex(&queueHead->mutex); if (queueHead->head == NULL) { PltUnlockMutex(&queueHead->mutex); return LBQ_NO_ELEMENT; } entry = queueHead->head; queueHead->head = entry->flink; queueHead->currentSize--; if (queueHead->head == NULL) { LC_ASSERT(queueHead->currentSize == 0); queueHead->tail = NULL; PltClearEvent(&queueHead->containsDataEvent); } else { LC_ASSERT(queueHead->currentSize != 0); queueHead->head->blink = NULL; } *data = entry->data; PltUnlockMutex(&queueHead->mutex); return LBQ_SUCCESS; }
int LbqOfferQueueItem(PLINKED_BLOCKING_QUEUE queueHead, void* data, PLINKED_BLOCKING_QUEUE_ENTRY entry) { entry->flink = NULL; entry->data = data; PltLockMutex(&queueHead->mutex); if (queueHead->currentSize == queueHead->sizeBound) { PltUnlockMutex(&queueHead->mutex); return LBQ_BOUND_EXCEEDED; } if (queueHead->head == NULL) { LC_ASSERT(queueHead->currentSize == 0); LC_ASSERT(queueHead->tail == NULL); queueHead->head = entry; queueHead->tail = entry; entry->blink = NULL; } else { LC_ASSERT(queueHead->currentSize >= 1); LC_ASSERT(queueHead->head != NULL); queueHead->tail->flink = entry; entry->blink = queueHead->tail; queueHead->tail = entry; } queueHead->currentSize++; PltUnlockMutex(&queueHead->mutex); PltSetEvent(&queueHead->containsDataEvent); return LBQ_SUCCESS; }
static void requestInvalidateReferenceFrames(void) { long long payload[3]; PQUEUED_FRAME_INVALIDATION_TUPLE qfit; LC_ASSERT(VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION); if (!getNextFrameInvalidationTuple(&qfit)) { return; } LC_ASSERT(qfit->startFrame <= qfit->endFrame); payload[0] = qfit->startFrame; payload[1] = qfit->endFrame; payload[2] = 0; // Aggregate all lost frames into one range do { LC_ASSERT(qfit->endFrame >= payload[1]); payload[1] = qfit->endFrame; free(qfit); } while (getNextFrameInvalidationTuple(&qfit)); // Send the reference frame invalidation request and read the response if (!sendMessageAndDiscardReply(packetTypes[IDX_INVALIDATE_REF_FRAMES], payloadLengths[IDX_INVALIDATE_REF_FRAMES], payload)) { Limelog("Request Invaldiate Reference Frames: Transaction failed: %d\n", (int) LastSocketError()); ListenerCallbacks.connectionTerminated(LastSocketError()); return; } Limelog("Invalidate reference frame request sent\n"); }
// newEntry is contained within the packet buffer so we free the whole entry by freeing entry->packet static int queuePacket(PRTP_REORDER_QUEUE queue, PRTP_QUEUE_ENTRY newEntry, int head, PRTP_PACKET packet) { if (queue->nextRtpSequenceNumber != UINT16_MAX) { PRTP_QUEUE_ENTRY entry; // Don't queue packets we're already ahead of if (isBeforeSignedInt(packet->sequenceNumber, queue->nextRtpSequenceNumber, 0)) { return 0; } // Don't queue duplicates either entry = queue->queueHead; while (entry != NULL) { if (entry->packet->sequenceNumber == packet->sequenceNumber) { return 0; } entry = entry->next; } } newEntry->packet = packet; newEntry->queueTimeMs = PltGetMillis(); newEntry->prev = NULL; newEntry->next = NULL; if (queue->oldestQueuedTimeMs == UINT64_MAX) { queue->oldestQueuedTimeMs = newEntry->queueTimeMs; queue->oldestQueuedEntry = newEntry; } if (queue->queueHead == NULL) { LC_ASSERT(queue->queueSize == 0); queue->queueHead = queue->queueTail = newEntry; } else if (head) { LC_ASSERT(queue->queueSize > 0); PRTP_QUEUE_ENTRY oldHead = queue->queueHead; newEntry->next = oldHead; LC_ASSERT(oldHead->prev == NULL); oldHead->prev = newEntry; queue->queueHead = newEntry; } else { LC_ASSERT(queue->queueSize > 0); PRTP_QUEUE_ENTRY oldTail = queue->queueTail; newEntry->prev = oldTail; LC_ASSERT(oldTail->next == NULL); oldTail->next = newEntry; queue->queueTail = newEntry; } queue->queueSize++; return 1; }
void cleanupPlatform(void) { cleanupPlatformSockets(); LC_ASSERT(thread_head == NULL); PltDeleteMutex(&thread_list_lock); }
void PltCloseThread(PLT_THREAD* thread) { PLT_THREAD* current_thread; PltLockMutex(&thread_list_lock); if (thread_head == thread) { // Remove the thread from the head thread_head = thread_head->next; } else { // Find the thread in the list current_thread = thread_head; while (current_thread != NULL) { if (current_thread->next == thread) { break; } current_thread = current_thread->next; } LC_ASSERT(current_thread != NULL); // Unlink this thread current_thread->next = thread->next; } PltUnlockMutex(&thread_list_lock); #if defined(LC_WINDOWS) CloseHandle(thread->termRequested); CloseHandle(thread->handle); #endif }
static PLT_THREAD* findCurrentThread(void) { PLT_THREAD* current_thread; PltLockMutex(&thread_list_lock); current_thread = thread_head; while (current_thread != NULL) { #if defined(LC_WINDOWS) if (current_thread->tid == GetCurrentThreadId()) { #else if (pthread_equal(current_thread->thread, pthread_self())) { #endif break; } current_thread = current_thread->next; } PltUnlockMutex(&thread_list_lock); LC_ASSERT(current_thread != NULL); return current_thread; } #endif int PltCreateMutex(PLT_MUTEX* mutex) { #if defined(LC_WINDOWS) *mutex = CreateMutexEx(NULL, NULL, 0, MUTEX_ALL_ACCESS); if (!*mutex) { return -1; } return 0; #else return pthread_mutex_init(mutex, NULL); #endif }
/** * Parse and set a JIT parameter. * * Parse a string of the form "<param>=<value>" where <param> must be * a JIT parameter (see Jit.h) and <value> must be an integer. * * @returns whether the parameter was parsed and set successfully. */ static bool parseJitParam(int32_t *param, const char *str) { /* JIT_P_STRING has the form: `(length of following string)(string)` */ const char *options = JIT_P_STRING; int i; for (i = 0; i < JIT_P__MAX; i++) { size_t len = *(const uint8_t *)options; LC_ASSERT(len > 0); if (strncmp(str, options + 1, len) == 0 && str[len] == '=') { int32_t value = 0; const char *p = &str[len+1]; while (*p >= '0' && *p <= '9') { value = value * 10 + (*p++ - '0'); } if (*p != 0) { /* Could not parse complete number. */ return false; } /* TODO: Validate range */ param[i] = value; return true; } options += 1 + len; } return false; }
int PltWaitForEvent(PLT_EVENT* event) { #if defined(LC_WINDOWS) DWORD error; HANDLE objects[2]; objects[0] = *event; objects[1] = findCurrentThread()->termRequested; error = WaitForMultipleObjectsEx(2, objects, FALSE, INFINITE, FALSE); if (error == WAIT_OBJECT_0) { return PLT_WAIT_SUCCESS; } else if (error == WAIT_OBJECT_0 + 1) { return PLT_WAIT_INTERRUPTED; } else { LC_ASSERT(0); return -1; } #else pthread_mutex_lock(&event->mutex); while (!event->signalled) { pthread_cond_wait(&event->cond, &event->mutex); } pthread_mutex_unlock(&event->mutex); return PLT_WAIT_SUCCESS; #endif }
void PltJoinThread(PLT_THREAD* thread) { LC_ASSERT(thread->cancelled); #if defined(LC_WINDOWS) WaitForSingleObjectEx(thread->handle, INFINITE, FALSE); #else pthread_join(thread->thread, NULL); #endif }
void PltLockMutex(PLT_MUTEX* mutex) { #if defined(LC_WINDOWS) int err; err = WaitForSingleObjectEx(*mutex, INFINITE, FALSE); if (err != WAIT_OBJECT_0) { LC_ASSERT(FALSE); } #else pthread_mutex_lock(mutex); #endif }
static void removeEntry(PRTP_REORDER_QUEUE queue, PRTP_QUEUE_ENTRY entry) { LC_ASSERT(entry != NULL); LC_ASSERT(queue->queueSize > 0); LC_ASSERT(queue->queueHead != NULL); LC_ASSERT(queue->queueTail != NULL); if (queue->queueHead == entry) { queue->queueHead = entry->next; } if (queue->queueTail == entry) { queue->queueTail = entry->prev; } if (entry->prev != NULL) { entry->prev->next = entry->next; } if (entry->next != NULL) { entry->next->prev = entry->prev; } queue->queueSize--; }
int LbqWaitForQueueElement(PLINKED_BLOCKING_QUEUE queueHead, void** data) { PLINKED_BLOCKING_QUEUE_ENTRY entry; int err; for (;;) { err = PltWaitForEvent(&queueHead->containsDataEvent); if (err != PLT_WAIT_SUCCESS) { return LBQ_INTERRUPTED; } PltLockMutex(&queueHead->mutex); if (queueHead->head == NULL) { PltClearEvent(&queueHead->containsDataEvent); PltUnlockMutex(&queueHead->mutex); continue; } entry = queueHead->head; queueHead->head = entry->flink; queueHead->currentSize--; if (queueHead->head == NULL) { LC_ASSERT(queueHead->currentSize == 0); queueHead->tail = NULL; PltClearEvent(&queueHead->containsDataEvent); } else { LC_ASSERT(queueHead->currentSize != 0); queueHead->head->blink = NULL; } *data = entry->data; PltUnlockMutex(&queueHead->mutex); break; } return LBQ_SUCCESS; }
// Start the video stream int startVideoStream(void* rendererContext, int drFlags) { int err; // This must be called before the decoder thread starts submitting // decode units LC_ASSERT(NegotiatedVideoFormat != 0); VideoCallbacks.setup(NegotiatedVideoFormat, StreamConfig.width, StreamConfig.height, StreamConfig.fps, rendererContext, drFlags); rtpSocket = bindUdpSocket(RemoteAddr.ss_family, RTP_RECV_BUFFER); if (rtpSocket == INVALID_SOCKET) { return LastSocketError(); } err = PltCreateThread(ReceiveThreadProc, NULL, &receiveThread); if (err != 0) { return err; } if ((VideoCallbacks.capabilities & CAPABILITY_DIRECT_SUBMIT) == 0) { err = PltCreateThread(DecoderThreadProc, NULL, &decoderThread); if (err != 0) { return err; } } if (ServerMajorVersion == 3) { // Connect this socket to open port 47998 for our ping thread firstFrameSocket = connectTcpSocket(&RemoteAddr, RemoteAddrLen, FIRST_FRAME_PORT, FIRST_FRAME_TIMEOUT_SEC); if (firstFrameSocket == INVALID_SOCKET) { return LastSocketError(); } } // Start pinging before reading the first frame so GFE knows where // to send UDP data err = PltCreateThread(UdpPingThreadProc, NULL, &udpPingThread); if (err != 0) { return err; } if (ServerMajorVersion == 3) { // Read the first frame to start the flow of video err = readFirstFrame(); if (err != 0) { return err; } } return 0; }
Closure * loadClosure(const char *filename, FILE *f, const StringTabEntry *strings, HashTable *itbls, HashTable *closures) { u4 i; u4 magic = fget_u4(f); assert(magic == CLOSURE_MAGIC); char *clos_name = loadId(f, strings, "."); u4 payloadsize = fget_varuint(f); char *itbl_name = loadId(f, strings, "."); Closure *cl = allocStaticClosure(wordsof(ClosureHeader) + payloadsize); Closure *fwd_ref; InfoTable* info = HashTable_lookup(itbls, itbl_name); LC_ASSERT(info != NULL && info->type != INVALID_OBJECT); // Fill in closure payload. May create forward references to // the current closure. setInfo(cl, info); xfree(itbl_name); for (i = 0; i < payloadsize; i++) { LD_DBG_PR(1, "Loading payload for: %s [%d]\n", clos_name, i); u1 dummy; loadLiteral(filename, f, &dummy, &cl->payload[i], strings, itbls, closures); } fwd_ref = HashTable_lookup(closures, clos_name); if (fwd_ref != NULL) { LD_DBG_PR(2, "Fixing closure forward ref: %s, %p -> %p\n", clos_name, fwd_ref, cl); // fixup forward refs void **p, *next; for (p = (void**)fwd_ref->payload[0]; p != NULL; p = next) { next = *p; *p = (void*)cl; } xfree(fwd_ref); HashTable_update(closures, clos_name, cl); // The key has been allocated by whoever installed the first // forward reference. xfree(clos_name); } else { HashTable_insert(closures, clos_name, cl); } return cl; }
SOCKET bindUdpSocket(int addrfamily) { SOCKET s; struct sockaddr_storage addr; int val; int err; LC_ASSERT(addrfamily == AF_INET || addrfamily == AF_INET6); s = socket(addrfamily, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { Limelog("socket() failed: %d\n", (int)LastSocketError()); return INVALID_SOCKET; } memset(&addr, 0, sizeof(addr)); addr.ss_family = addrfamily; if (bind(s, (struct sockaddr*) &addr, addrfamily == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) == SOCKET_ERROR) { err = LastSocketError(); Limelog("bind() failed: %d\n", err); closesocket(s); SetLastSocketError(err); return INVALID_SOCKET; } #ifdef LC_DARWIN // Disable SIGPIPE on iOS val = 1; setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char* )&val, sizeof(val)); #endif // Set the receive buffer to 64KB by default val = 65536; setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*) &val, sizeof(val)); return s; }
// This shim callback runs the client's connectionTerminated() callback on a // separate thread. This is neccessary because other internal threads directly // invoke this callback. That can result in a deadlock if the client // calls LiStopConnection() in the callback when the cleanup code // attempts to join the thread that the termination callback (and LiStopConnection) // is running on. static void ClInternalConnectionTerminated(long errorCode) { int err; // Avoid recursion and issuing multiple callbacks if (alreadyTerminated) { return; } alreadyTerminated = 1; // Invoke the termination callback on a separate thread err = PltCreateThread(terminationCallbackThreadFunc, NULL, &terminationCallbackThread); if (err != 0) { // Nothing we can safely do here, so we'll just assert on debug builds Limelog("Failed to create termination thread: %d\n", err); LC_ASSERT(err == 0); } // Close the thread handle since we can never wait on it PltCloseThread(&terminationCallbackThread); }
InfoTable * loadInfoTable(const char *filename, FILE *f, const StringTabEntry *strings, HashTable *itbls, HashTable *closures) { u4 magic = fget_u4(f); assert(magic == INFO_MAGIC); char *itbl_name = loadId(f, strings, "."); u2 cl_type = fget_varuint(f); InfoTable *new_itbl = NULL; FwdRefInfoTable *old_itbl = HashTable_lookup(itbls, itbl_name); if (old_itbl && old_itbl->i.type != INVALID_OBJECT) { fprintf(stderr, "ERROR: Duplicate info table: %s\n", itbl_name); exit(1); } switch (cl_type) { case CONSTR: // A statically allocated constructor { ConInfoTable *info = allocInfoTable(wordsof(ConInfoTable)); info->i.type = cl_type; info->i.tagOrBitmap = fget_varuint(f); // tag Word sz = fget_varuint(f); assert(sz <= 32); info->i.size = sz; info->i.layout.bitmap = sz > 0 ? fget_u4(f) : 0; // info->i.layout.payload.ptrs = fget_varuint(f); // info->i.layout.payload.nptrs = fget_varuint(f); info->name = loadId(f, strings, "."); new_itbl = (InfoTable*)info; } break; case FUN: { FuncInfoTable *info = allocInfoTable(wordsof(FuncInfoTable)); info->i.type = cl_type; info->i.tagOrBitmap = 0; // TODO: anything useful to put in here? Word sz = fget_varuint(f); assert(sz <= 32); info->i.size = sz; info->i.layout.bitmap = sz > 0 ? fget_u4(f) : 0; info->name = loadId(f, strings, "."); loadCode(filename, f, &info->code, strings, itbls, closures); new_itbl = (InfoTable*)info; } break; case CAF: case THUNK: { ThunkInfoTable *info = allocInfoTable(wordsof(ThunkInfoTable)); info->i.type = cl_type; info->i.tagOrBitmap = 0; // TODO: anything useful to put in here? Word sz = fget_varuint(f); assert(sz <= 32); info->i.size = sz; info->i.layout.bitmap = sz > 0 ? fget_u4(f) : 0; info->name = loadId(f, strings, "."); loadCode(filename, f, &info->code, strings, itbls, closures); new_itbl = (InfoTable*)info; } break; default: fprintf(stderr, "ERROR: Unknown info table type (%d)", cl_type); exit(1); } // new_itbl is the new info table. There may have been forward // references (even during loading the code for this info table). if (old_itbl != NULL) { LD_DBG_PR(1, "Fixing itable forward reference for: %s, %p\n", itbl_name, new_itbl); void **p, *next; LC_ASSERT(old_itbl->i.type == INVALID_OBJECT); for (p = old_itbl->next; p != NULL; p = next) { next = *p; *p = (void*)new_itbl; } // TODO: fixup forward refs xfree(old_itbl); HashTable_update(itbls, itbl_name, new_itbl); xfree(itbl_name); } else { HashTable_insert(itbls, itbl_name, new_itbl); } return new_itbl; }
int irEngine(Capability *cap, Fragment *F) { static Inst disp[] = { #define IRIMPL(name, f, o1, o2) &&op_##name, IRDEF(IRIMPL) #undef IRIMPL &&stop }; IRRef ref; Thread *T = cap->T; Word nphis = F->nphis; Word *base = T->base - 1; Word szins = F->nins - F->nk; Word vals_[szins + nphis]; Word *phibuf = &vals_[szins]; /* For parallel copy of PHI nodes */ Word *vals = vals_ - (int)F->nk; IRIns *pc = F->ir + REF_FIRST; IRRef pcref = REF_FIRST; IRIns *pcmax = F->ir + F->nins; IRIns *pcloop = F->nloop ? F->ir + F->nloop + 1 : pc; //int count = 100; DBG_PR("*** Executing trace.\n" "*** base = %p\n" "*** pc = %p\n" "*** pcmax = %p (%d)\n" "*** loop = %p (%d)\n", base, pc, pcmax, (int)(pcmax - pc), pcloop, (int)(pcloop - pc)); for (ref = F->nk; ref < REF_BIAS; ref++) { switch (IR(ref)->o) { case IR_KINT: vals[ref] = (Word)IR(ref)->i; break; case IR_KBASEO: vals[ref] = (Word)(T->base + IR(ref)->i); break; case IR_KWORD: vals[ref] = (Word)(F->kwords[IR(ref)->u]); break; default: LC_ASSERT(0); break; } DBG_LVL(2, "%d, %" FMT_WordX "\n", ref - REF_BIAS, vals[ref]); } vals[REF_BASE] = (Word)base; goto *disp[pc->o]; # define DISPATCH_NEXT \ if (irt_type(pc->t) != IRT_VOID && pc->o != IR_PHI) { \ if (irt_type(pc->t) == IRT_I32) \ DBG_LVL(2, " ===> %" FMT_Int "\n", vals[pcref]); \ else \ DBG_LVL(2, " ===> 0x%" FMT_WordX "\n", vals[pcref]); } \ ++pc; ++pcref; \ if (LC_UNLIKELY(pc >= pcmax)) { pc = pcloop; pcref = F->nloop + 1; } \ if (pc->o != IR_NOP) { \ DBG_LVL(2, "[%d] ", pcref - REF_BIAS); \ IF_DBG_LVL(2, printIR(F, *pc)); } \ goto *disp[pc->o] op_NOP: op_FRAME: op_RET: op_LOOP: DISPATCH_NEXT; op_PHI: { /* PHI nodes represent parallel assignments, so as soon as we discover the first PHI node, we perform all assignments in parallel. */ LC_ASSERT(nphis > 0); u2 i; DBG_LVL(3, " ( "); for (i = 0; i < nphis; i++) { DBG_LVL(3, "%d ", irref_int(pc[i].op2)); phibuf[i] = vals[pc[i].op2]; } DBG_LVL(3, ") --> ( "); for (i = 0; i < nphis; i++) { DBG_LVL(3, "%d ", irref_int(pc[i].op1)); vals[pc[i].op1] = phibuf[i]; } DBG_LVL(3, ") [%d phis]\n", (int)nphis); pc += nphis - 1; //vals[pc->op1] = vals[pc->op2]; DISPATCH_NEXT; } op_LT: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] < (WordInt)vals[pc->op2])) goto guard_failed; DISPATCH_NEXT; op_GE: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] >= (WordInt)vals[pc->op2])) goto guard_failed; DISPATCH_NEXT; op_LE: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] <= (WordInt)vals[pc->op2])) goto guard_failed; DISPATCH_NEXT; op_GT: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] > (WordInt)vals[pc->op2])) goto guard_failed; DISPATCH_NEXT; op_EQ: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] == (WordInt)vals[pc->op2])) { goto guard_failed; } DISPATCH_NEXT; op_NE: recordEvent(EV_CMP, 0); if (!((WordInt)vals[pc->op1] != (WordInt)vals[pc->op2])) goto guard_failed; DISPATCH_NEXT; op_ADD: recordEvent(EV_ALU, 0); vals[pcref] = vals[pc->op1] + vals[pc->op2]; DISPATCH_NEXT; op_SUB: recordEvent(EV_ALU, 0); vals[pcref] = vals[pc->op1] - vals[pc->op2]; DISPATCH_NEXT; op_MUL: recordEvent(EV_MUL, 0); vals[pcref] = (WordInt)vals[pc->op1] * (WordInt)vals[pc->op2]; DISPATCH_NEXT; op_DIV: recordEvent(EV_REMDIV, 0); if (LC_LIKELY(vals[pc->op2] != 0)) vals[pcref] = (WordInt)vals[pc->op1] / (WordInt)vals[pc->op2]; else LC_ASSERT(0); DISPATCH_NEXT; op_REM: recordEvent(EV_REMDIV, 0); if (LC_LIKELY(vals[pc->op2] != 0)) vals[pcref] = (WordInt)vals[pc->op1] % (WordInt)vals[pc->op2]; else LC_ASSERT(0); DISPATCH_NEXT; op_FREF: vals[pcref] = (Word)(((Closure*)vals[pc->op1])->payload + (pc->op2 - 1)); DISPATCH_NEXT; op_FLOAD: recordEvent(EV_LOAD, 0); vals[pcref] = *((Word*)vals[pc->op1]); DISPATCH_NEXT; op_SLOAD: recordEvent(EV_LOAD, 0); vals[pcref] = base[pc->op1]; DISPATCH_NEXT; op_ILOAD: recordEvent(EV_LOAD, 0); vals[pcref] = (Word)getInfo(vals[pc->op1]); DISPATCH_NEXT; op_NEW: if (!ir_issunken(pc)) { // do actual allocation on trace HeapInfo *hp = &F->heap[pc->op2]; int j; recordEvent(EV_ALLOC, hp->nfields + 1); Closure *cl = allocClosure(wordsof(ClosureHeader) + hp->nfields); setInfo(cl, (InfoTable*)vals[pc->op1]); for (j = 0; j < hp->nfields; j++) { cl->payload[j] = vals[getHeapInfoField(F, hp, j)]; } vals[pcref] = (Word)cl; } else { vals[pcref] = 0; // to trigger an error if accessed } DISPATCH_NEXT; op_UPDATE: { recordEvent(EV_UPDATE, 0); Closure *oldnode = (Closure *)vals[pc->op1]; Closure *newnode = (Closure *)base[pc->op2]; setInfo(oldnode, (InfoTable*)&stg_IND_info); oldnode->payload[0] = (Word)newnode; DISPATCH_NEXT; } op_RLOAD: op_FSTORE: op_RENAME: op_BNOT: op_BAND: op_BOR: op_BXOR: op_BSHL: op_BSHR: op_BSAR: op_BROL: op_BROR: // These should never be executed. op_BASE: op_KINT: op_KWORD: op_KBASEO: LC_ASSERT(0); guard_failed: DBG_PR("Exiting at %d\n", pcref - REF_BIAS); { int i; SnapShot *snap = 0; SnapEntry *se; for (i = 0; i < F->nsnap; i++) { if (F->snap[i].ref == pcref) { snap = &F->snap[i]; break; } } LC_ASSERT(snap != 0); snap->count++; se = F->snapmap + snap->mapofs; DBG_PR("Snapshot: %d, Snap entries: %d, slots = %d\n", i, snap->nent, snap->nslots); recordEvent(EV_EXIT, snap->nent); for (i = 0; i < snap->nent; i++, se++) { BCReg s = snap_slot(*se); IRRef r = snap_ref(*se); DBG_PR("base[%d] = ", s - 1); base[s] = restoreValue(F, vals, r); IF_DBG_LVL(1, printSlot(stderr, base + s); fprintf(stderr, "\n")); //DBG_PR("0x%" FMT_WordX "\n", base[s]); } DBG_PR("Base slot: %d\n", se[1]); // se[1] = T->pc = (BCIns *)F->startpc + (int)se[0]; T->base = base + se[1]; T->top = base + snap->nslots; //printFrame(T->base, T->top); return 0; } stop: return 1; }
/* Stop the connection by undoing the step at the current stage and those before it */ void LiStopConnection(void) { // Disable termination callbacks now alreadyTerminated = 1; if (stage == STAGE_INPUT_STREAM_START) { Limelog("Stopping input stream..."); stopInputStream(); stage--; Limelog("done\n"); } if (stage == STAGE_AUDIO_STREAM_START) { Limelog("Stopping audio stream..."); stopAudioStream(); stage--; Limelog("done\n"); } if (stage == STAGE_VIDEO_STREAM_START) { Limelog("Stopping video stream..."); stopVideoStream(); stage--; Limelog("done\n"); } if (stage == STAGE_CONTROL_STREAM_START) { Limelog("Stopping control stream..."); stopControlStream(); stage--; Limelog("done\n"); } if (stage == STAGE_INPUT_STREAM_INIT) { Limelog("Cleaning up input stream..."); destroyInputStream(); stage--; Limelog("done\n"); } if (stage == STAGE_AUDIO_STREAM_INIT) { Limelog("Cleaning up audio stream..."); destroyAudioStream(); stage--; Limelog("done\n"); } if (stage == STAGE_VIDEO_STREAM_INIT) { Limelog("Cleaning up video stream..."); destroyVideoStream(); stage--; Limelog("done\n"); } if (stage == STAGE_CONTROL_STREAM_INIT) { Limelog("Cleaning up control stream..."); destroyControlStream(); stage--; Limelog("done\n"); } if (stage == STAGE_RTSP_HANDSHAKE) { Limelog("Terminating RTSP handshake..."); terminateRtspHandshake(); stage--; Limelog("done\n"); } if (stage == STAGE_NAME_RESOLUTION) { // Nothing to do stage--; } if (stage == STAGE_PLATFORM_INIT) { Limelog("Cleaning up platform..."); cleanupPlatform(); stage--; Limelog("done\n"); } LC_ASSERT(stage == STAGE_NONE); }
/* Starts the connection to the streaming machine */ int LiStartConnection(const char* host, PSTREAM_CONFIGURATION streamConfig, PCONNECTION_LISTENER_CALLBACKS clCallbacks, PDECODER_RENDERER_CALLBACKS drCallbacks, PAUDIO_RENDERER_CALLBACKS arCallbacks, void* renderContext, int drFlags, int _serverMajorVersion) { int err; ServerMajorVersion = _serverMajorVersion; memcpy(&StreamConfig, streamConfig, sizeof(StreamConfig)); // Replace missing callbacks with placeholders fixupMissingCallbacks(&drCallbacks, &arCallbacks, &clCallbacks); memcpy(&VideoCallbacks, drCallbacks, sizeof(VideoCallbacks)); memcpy(&AudioCallbacks, arCallbacks, sizeof(AudioCallbacks)); // Hook the termination callback so we can avoid issuing a termination callback // after LiStopConnection() is called originalTerminationCallback = clCallbacks->connectionTerminated; memcpy(&ListenerCallbacks, clCallbacks, sizeof(ListenerCallbacks)); ListenerCallbacks.connectionTerminated = ClInternalConnectionTerminated; alreadyTerminated = 0; Limelog("Initializing platform..."); ListenerCallbacks.stageStarting(STAGE_PLATFORM_INIT); err = initializePlatform(); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_PLATFORM_INIT, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_PLATFORM_INIT); ListenerCallbacks.stageComplete(STAGE_PLATFORM_INIT); Limelog("done\n"); Limelog("Resolving host name..."); ListenerCallbacks.stageStarting(STAGE_NAME_RESOLUTION); err = resolveHostName(host); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_NAME_RESOLUTION, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_NAME_RESOLUTION); ListenerCallbacks.stageComplete(STAGE_NAME_RESOLUTION); Limelog("done\n"); Limelog("Starting RTSP handshake..."); ListenerCallbacks.stageStarting(STAGE_RTSP_HANDSHAKE); err = performRtspHandshake(); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_RTSP_HANDSHAKE, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_RTSP_HANDSHAKE); ListenerCallbacks.stageComplete(STAGE_RTSP_HANDSHAKE); Limelog("done\n"); Limelog("Initializing control stream..."); ListenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_INIT); err = initializeControlStream(); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_INIT, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_CONTROL_STREAM_INIT); ListenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_INIT); Limelog("done\n"); Limelog("Initializing video stream..."); ListenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_INIT); initializeVideoStream(); stage++; LC_ASSERT(stage == STAGE_VIDEO_STREAM_INIT); ListenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_INIT); Limelog("done\n"); Limelog("Initializing audio stream..."); ListenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_INIT); initializeAudioStream(); stage++; LC_ASSERT(stage == STAGE_AUDIO_STREAM_INIT); ListenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_INIT); Limelog("done\n"); Limelog("Initializing input stream..."); ListenerCallbacks.stageStarting(STAGE_INPUT_STREAM_INIT); initializeInputStream(streamConfig->remoteInputAesKey, sizeof(streamConfig->remoteInputAesKey), streamConfig->remoteInputAesIv, sizeof(streamConfig->remoteInputAesIv)); stage++; LC_ASSERT(stage == STAGE_INPUT_STREAM_INIT); ListenerCallbacks.stageComplete(STAGE_INPUT_STREAM_INIT); Limelog("done\n"); Limelog("Starting control stream..."); ListenerCallbacks.stageStarting(STAGE_CONTROL_STREAM_START); err = startControlStream(); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_CONTROL_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_CONTROL_STREAM_START); ListenerCallbacks.stageComplete(STAGE_CONTROL_STREAM_START); Limelog("done\n"); Limelog("Starting video stream..."); ListenerCallbacks.stageStarting(STAGE_VIDEO_STREAM_START); err = startVideoStream(renderContext, drFlags); if (err != 0) { Limelog("Video stream start failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_VIDEO_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_VIDEO_STREAM_START); ListenerCallbacks.stageComplete(STAGE_VIDEO_STREAM_START); Limelog("done\n"); Limelog("Starting audio stream..."); ListenerCallbacks.stageStarting(STAGE_AUDIO_STREAM_START); err = startAudioStream(); if (err != 0) { Limelog("Audio stream start failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_AUDIO_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_AUDIO_STREAM_START); ListenerCallbacks.stageComplete(STAGE_AUDIO_STREAM_START); Limelog("done\n"); Limelog("Starting input stream..."); ListenerCallbacks.stageStarting(STAGE_INPUT_STREAM_START); err = startInputStream(); if (err != 0) { Limelog("Input stream start failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_INPUT_STREAM_START, err); goto Cleanup; } stage++; LC_ASSERT(stage == STAGE_INPUT_STREAM_START); ListenerCallbacks.stageComplete(STAGE_INPUT_STREAM_START); Limelog("done\n"); ListenerCallbacks.connectionStarted(); Cleanup: return err; }
// Load the module and Module * loadModuleHeader(FILE *f, const char *filename) { Module *mdl; char magic[5]; u2 major, minor; u4 flags; u4 secmagic; u4 i; LC_ASSERT(f != NULL); fread(magic, 4, 1, f); magic[4] = '\0'; if (strcmp(magic, "KHCB") != 0) { fprintf(stderr, "ERROR: Module '%s' is not a bytecode file. %s\n", filename, magic); exit(1); } mdl = xmalloc(sizeof(Module)); major = fget_u2(f); minor = fget_u2(f); if (major != VERSION_MAJOR || minor != VERSION_MINOR) { fprintf(stderr, "ERROR: Module '%s' version mismatch. Version: %d.%d, Expected: %d.%d\n", filename, major, minor, VERSION_MAJOR, VERSION_MINOR); exit(1); } flags = fget_u4(f); mdl->numStrings = fget_u4(f); mdl->numInfoTables = fget_u4(f); mdl->numClosures = fget_u4(f); mdl->numImports = fget_u4(f); //printf("strings = %d, itbls = %d, closures = %d\n", // mdl->numStrings, mdl->numInfoTables, mdl->numClosures); // String table starts with a 4 byte magic. secmagic = fget_u4(f); assert(secmagic == STR_SEC_HDR_MAGIC); mdl->strings = xmalloc(sizeof(StringTabEntry) * mdl->numStrings); for (i = 0; i < mdl->numStrings; i++) { loadStringTabEntry(f, &mdl->strings[i]); } //printStringTable(mdl->strings, mdl->numStrings); mdl->name = loadId(f, mdl->strings, "."); // printf("mdl name = %s\n", mdl->name); mdl->imports = xmalloc(sizeof(*mdl->imports) * mdl->numImports); for (i = 0; i < mdl->numImports; i++) { mdl->imports[i] = loadId(f, mdl->strings, "."); // printf("import: %s\n", mdl->imports[i]); } return mdl; }