//return 0 on no error static int tskDataSourceOpen(ScalpelInputReader * const reader) { printVerbose("tskDataSourceOpen()\n"); JNIEnv * env = attachThread(); TskInputStreamSourceInfo * tskData = castTskDataSource(reader); if (!tskData) { setThrowScalpelException(* (env), "tskDataSourceOpen() - ERROR object not initialized"); detachThread(); return -1; } if (reader->isOpen) { fprintf(stdout, "tskDataSourceOpen() WARNING stream already open\n"); //already open, should really close first, reset jlong zerOff = env->CallLongMethod(tskData->jInputStream, tskData->jSeekMethodId, (jlong)0); fprintf(stdout, "tskDataSourceOpen() rewinded, new offset: %"PRI64 "\n", (long long) zerOff); } else if (!tskData->firstOpen) { //closed but had already been open, so need to rewind to start //const jlong jnewOff = jlong zerOff = env->CallLongMethod(tskData->jInputStream, tskData->jSeekMethodId, (jlong)0); fprintf(stdout, "tskDataSourceOpen() rewinded, new offset: %"PRI64 "\n", (long long) zerOff); } reader->isOpen = TRUE; tskData->firstOpen = FALSE; detachThread(); return 0; }
//return 0 on no-error static int tskDataSourceSeekO(ScalpelInputReader * const reader, long long offset, scalpel_SeekRel whence) { printVerbose("tskDataSourceSeekO()\n"); //fprintf (stdout, "tskDataSourceSeekO() offset: %"PRI64 "whence: %d\n", offset, whence); JNIEnv * env = attachThread(); const TskInputStreamSourceInfo * tskData = castTskDataSource(reader); if (!tskData) { setThrowScalpelException(* (env), "tskDataSourceSeekO() - ERROR object not initialized"); detachThread(); return -1; } jlong newOffset = 0; jlong joffRel = 0; switch (whence) { case SCALPEL_SEEK_SET: newOffset = offset; break; case SCALPEL_SEEK_CUR: //get cur joffRel = env->CallLongMethod(tskData->jInputStream, tskData->jGetPositionMethodId); newOffset = offset + joffRel; break; case SCALPEL_SEEK_END: //get size joffRel = env->CallLongMethod(tskData->jInputStream, tskData->jGetSizeMethodId); newOffset = joffRel - offset; //TODO verify if need -1 break; default: break; } if (newOffset < 0) { setThrowScalpelException(* (env), "tskDataSourceSeekO() - ERROR invalid negative resulting offset."); detachThread(); return -1; } //const jlong jnewOff = env->CallLongMethod(tskData->jInputStream, tskData->jSeekMethodId, newOffset); if (env->ExceptionCheck() ){ env->ExceptionDescribe(); env->ExceptionClear(); setThrowScalpelException(* (env), "tskDataSourceSeekO() - ERROR seek failed."); detachThread(); return -1; } detachThread(); //fprintf(stdout, "tskDataSourceSeekO() deltaOffset: %"PRI64", new offset: %"PRI64 "\n", newOffset, (long long) jnewOff); return 0; }
void* WorkerThread::workerThread() { { MutexLocker lock(m_threadCreationMutex); m_workerContext = createWorkerContext(m_startupData->m_scriptURL, m_startupData->m_userAgent); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerContext->script()->forbidExecution(); } } WorkerScriptController* script = m_workerContext->script(); script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData.clear(); runEventLoop(); ThreadIdentifier threadID = m_threadID; ASSERT(m_workerContext->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerContext = 0; // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); return 0; }
// Creates a separate thread to handle dispatching timer events. That 'timer' thread registers a signal // handler for SIGALRM signals and then waits on a semaphore indefinitely. The semaphore is unlocked when // the signal handler is invoked. The timer thread subsequently gets unblocked from the semaphore wait // and then invokes the 'timerEventCallback' callback which is used to indicate that a timer event has // occurred. Upon timer notice, the platform should invoke the fireTimerIfNeeded() routine which basically // invokes the 'sharedTimerFiredFunction' callback, which is the actual WebCore callback routine to // execute upon timer expiration. void setSharedTimerFiredFunction(void (*callbackFunc)()) { ASSERT(callbackFunc); if (timerEventCallback == NULL) { LOG_ERROR("timerEventCallback is NULL"); exit(1); } if (sharedTimerFiredFunction == NULL) { sharedTimerFiredFunction = callbackFunc; LOG_ERROR_ON_FAILURE_AND_EXIT(sem_init(&threadReadySem, 0, 0)); ASSERT(isMainThread()); // Create a separate thread to signal timer events through the timerEventCallback function ThreadIdentifier timerThreadID = createThread(timerThreadEntryPoint, NULL, "WebCore: Timers"); if (!timerThreadID) { LOG_ERROR("Timer thread creation failed\n"); exit(1); } // Synchronously wait for the timer thread to signal it's now ready to handle timer signals - // this prevents dropping early timer requests from WebCore LOG_ERROR_ON_FAILURE(sem_wait(&threadReadySem)); detachThread(timerThreadID); } }
void *threadStart(void *arg) { Thread *thread = (Thread *)arg; //Object *jThread = thread->ee->thread; Object *jThread = thread->thread; /* Parent thread created thread with suspension disabled. This is inherited so we need to enable */ enableSuspend(thread); /* Complete initialisation of the thread structure, create the thread stack and add the thread to the thread list */ initThread(thread, INST_DATA(jThread)[daemon_offset], &thread); /* Add thread to thread ID map hash table. */ addThreadToHash(thread); /* Execute the thread's run method */ DummyFrame dummy; executeMethod(&dummy, jThread, CLASS_CB(jThread->classobj)->method_table[run_mtbl_idx]); /* Run has completed. Detach the thread from the VM and exit */ detachThread(thread); TRACE("Thread 0x%x id: %d exited\n", thread, thread->id); return NULL; }
static bool attachThreadToForeground() { // only attach threads if using low level hooks. a low level hook // runs in the thread that installed the hook but we have to make // changes that require being attached to the target thread (which // should be the foreground window). a regular hook runs in the // thread that just removed the event from its queue so we're // already in the right thread. if (g_hookThread != 0) { HWND window = GetForegroundWindow(); DWORD threadID = GetWindowThreadProcessId(window, NULL); // skip if no change if (g_attachedThread != threadID) { // detach from previous thread detachThread(); // attach to new thread if (threadID != 0 && threadID != g_hookThread) { AttachThreadInput(g_hookThread, threadID, TRUE); g_attachedThread = threadID; } return true; } } return false; }
void LocalFileTransferAPI::threadFct() { FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this); char buffer[BUFFER_SIZE]; std::streamsize readSize = 1; try { mSourceFileStream.open(mSourceFileStr.c_str(), std::ios_base::in | std::ios_base::binary); if(mSourceFileStream.fail()) { FBLOG_DEBUG("LocalFileTransferAPI::start", "Can't open the source file: " << mSourceFileStr); onError("Can't open the source file"); throw std::runtime_error("Can't open the source file"); } mTargetFileStream.open(mTargetFileStr.c_str(), std::ios_base::out | std::ios_base::binary); if(mTargetFileStream.fail()) { FBLOG_DEBUG("LocalFileTransferAPI::start", "Can't open the target file: " << mTargetFileStr); onError("Can't open the target file"); throw std::runtime_error("Can't open the target file"); } mSourceFileStream.seekg (0, std::ifstream::end); mTotalBytes = mSourceFileStream.tellg(); mSourceFileStream.seekg (0, std::ifstream::beg); boost::this_thread::disable_interruption di; while(!boost::this_thread::interruption_requested() && readSize > 0) { readSize = mTotalBytes - mTransferedBytes; if(readSize > BUFFER_SIZE) readSize = BUFFER_SIZE; mSourceFileStream.read(buffer, readSize); readSize = mSourceFileStream.gcount(); if(mSourceFileStream.fail()) { FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this << " | Can't read the source file" << mSourceFileStream.rdstate()); onError("Can't read the source file"); throw std::runtime_error("Can't read the source file"); } FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this << " | Read " << readSize << "(" << mTransferedBytes << " of " << mTotalBytes << ")"); mTransferedBytes += readSize; mTargetFileStream.write(buffer, readSize); if(mTargetFileStream.fail()) { FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this << " | Can't write the target file " << mTargetFileStream.rdstate()); onError("Can't write the target file"); throw std::runtime_error("Can't write the target file"); } } if(mTransferedBytes != mTotalBytes) { FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this << " | Incomplet transfer"); onError("Incomplet transfer"); throw std::runtime_error("Incomplet transfer"); } mSourceFileStream.close(); mTargetFileStream.close(); FBLOG_DEBUG("LocalFileTransferAPI::threadFct", "this=" << this << " | Done"); onSuccess(true); } catch(std::runtime_error&) { mSourceFileStream.close(); mTargetFileStream.close(); // Nothing to do } detachThread(boost::this_thread::get_id()); mThread.reset(); }
void* DatabaseThread::databaseThread() { LOG(StorageAPI, "Starting DatabaseThread %p", this); AutodrainedPool pool; while (true) { RefPtr<DatabaseTask> task; if (!m_queue.waitForMessage(task)) break; task->performTask(); pool.cycle(); } LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); // Detach the thread so its resources are no longer of any concern to anyone else detachThread(m_threadID); // Clear the self refptr, possibly resulting in deletion m_selfRef = 0; return 0; }
SteamCallbackAdapter::~SteamCallbackAdapter() { if (m_callback != 0) { JNIEnv* env = attachThread(); env->DeleteGlobalRef(m_callback); detachThread(); } }
void ThreadedCompositor::runCompositingThread() { { LockHolder locker(m_initializeRunLoopConditionLock); m_compositingRunLoop = std::make_unique<CompositingRunLoop>([&] { renderLayerTree(); }); m_scene = adoptRef(new CoordinatedGraphicsScene(this)); m_viewportController = std::make_unique<SimpleViewportController>(this); m_initializeRunLoopCondition.notifyOne(); } m_compositingRunLoop->runLoop().run(); m_compositingRunLoop->stopUpdates(); m_scene->purgeGLResources(); { LockHolder locker(m_terminateRunLoopConditionLock); m_compositingRunLoop = nullptr; m_context = nullptr; m_scene = nullptr; m_terminateRunLoopCondition.notifyOne(); } detachThread(m_threadIdentifier); }
//return size, or -1 on error static long long tskDataSourceGetSize(ScalpelInputReader * const reader) { printVerbose("tskDataSourceGetSize()\n"); JNIEnv * env = attachThread(); const TskInputStreamSourceInfo * tskData = castTskDataSource(reader); if (!tskData) { setThrowScalpelException(* (env), "tskDataSourceGetSize() - ERROR object not initialized"); detachThread(); return -1; } const jlong jsize = env->CallLongMethod(tskData->jInputStream, tskData->jGetSizeMethodId); detachThread(); return (long long) jsize; }
static unsigned long long tskDataSourceTellO(ScalpelInputReader * const reader) { printVerbose("tskDataSourceTellO()\n"); JNIEnv * env = attachThread(); const TskInputStreamSourceInfo * tskData = castTskDataSource(reader); if (!tskData) { setThrowScalpelException(*env, "tskDataSourceTellO() - ERROR object not initialized"); detachThread(); return 0; } const jlong joff = env->CallLongMethod(tskData->jInputStream, tskData->jGetPositionMethodId); detachThread(); fprintf(stdout, "tskDataSourceTellO() ret %"PRIu64 "\n", joff ); return (unsigned long long) joff; }
void AutomaticThread::start(const LockHolder&) { RELEASE_ASSERT(m_isRunning); RefPtr<AutomaticThread> preserveThisForThread = this; m_hasUnderlyingThread = true; ThreadIdentifier thread = createThread( "WTF::AutomaticThread", [=] () { if (verbose) dataLog(RawPointer(this), ": Running automatic thread!\n"); ThreadScope threadScope(preserveThisForThread); if (!ASSERT_DISABLED) { LockHolder locker(*m_lock); ASSERT(!m_condition->contains(locker, this)); } auto stop = [&] (const LockHolder&) { m_isRunning = false; m_isRunningCondition.notifyAll(); }; for (;;) { { LockHolder locker(*m_lock); for (;;) { PollResult result = poll(locker); if (result == PollResult::Work) break; if (result == PollResult::Stop) return stop(locker); RELEASE_ASSERT(result == PollResult::Wait); // Shut the thread down after one second. bool awokenByNotify = m_condition->m_condition.waitFor(*m_lock, 1_s); if (!awokenByNotify) { if (verbose) dataLog(RawPointer(this), ": Going to sleep!\n"); m_condition->add(locker, this); return; } } } WorkResult result = work(); if (result == WorkResult::Stop) { LockHolder locker(*m_lock); return stop(locker); } RELEASE_ASSERT(result == WorkResult::Continue); } }); detachThread(thread); }
void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone) { ThreadIdentifier threadID = createThread(collect, 0, "WebCore: GCController"); if (waitUntilDone) { waitForThreadCompletion(threadID); return; } detachThread(threadID); }
void MemoryPressureHandler::uninstall() { if (!m_installed) return; if (m_threadID) { detachThread(m_threadID); m_threadID = 0; } logErrorAndCloseFDs(nullptr); m_installed = false; }
void WorkerThread::workerThread() { // Propagate the mainThread's fenv to workers. #if PLATFORM(IOS) FloatingPointEnvironment::singleton().propagateMainThreadEnvironment(); #endif #if PLATFORM(GTK) GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new()); g_main_context_push_thread_default(mainContext.get()); #endif { LockHolder lock(m_threadCreationMutex); m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_shouldBypassMainWorldContentSecurityPolicy, WTFMove(m_startupData->m_topOrigin)); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerGlobalScope->script()->forbidExecution(); } } WorkerScriptController* script = m_workerGlobalScope->script(); script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData = nullptr; runEventLoop(); #if PLATFORM(GTK) g_main_context_pop_thread_default(mainContext.get()); #endif ThreadIdentifier threadID = m_threadID; ASSERT(m_workerGlobalScope->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerGlobalScope = nullptr; // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! threadGlobalData().destroy(); // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); }
void WorkQueue::platformInvalidate() { { LockHolder locker(m_terminateRunLoopConditionMutex); if (m_runLoop) { m_runLoop->stop(); m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex); } } if (m_workQueueThread) { detachThread(m_workQueueThread); m_workQueueThread = 0; } }
void DatabaseThread::databaseThread() { { // Wait for DatabaseThread::start() to complete. LockHolder lock(m_threadCreationMutex); LOG(StorageAPI, "Started DatabaseThread %p", this); } while (auto task = m_queue.waitForMessage()) { AutodrainedPool pool; task->performTask(); } // Clean up the list of all pending transactions on this database thread m_transactionCoordinator->shutdown(); LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); // Close the databases that we ran transactions on. This ensures that if any transactions are still open, they are rolled back and we don't leave the database in an // inconsistent or locked state. DatabaseSet openSetCopy; { LockHolder lock(m_openDatabaseSetMutex); if (m_openDatabaseSet.size() > 0) { // As the call to close will modify the original set, we must take a copy to iterate over. openSetCopy.swap(m_openDatabaseSet); } } for (auto& openDatabase : openSetCopy) openDatabase->close(); // Detach the thread so its resources are no longer of any concern to anyone else detachThread(m_threadID); DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync; // Clear the self refptr, possibly resulting in deletion m_selfRef = nullptr; if (cleanupSync) // Someone wanted to know when we were done cleaning up. cleanupSync->taskCompleted(); }
void WorkerThread::workerThread() { // Propagate the mainThread's fenv to workers. #if PLATFORM(IOS) fesetenv(&mainThreadFEnv); #endif { MutexLocker lock(m_threadCreationMutex); m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, std::move(m_startupData->m_groupSettings), m_startupData->m_contentSecurityPolicy, m_startupData->m_contentSecurityPolicyType, m_startupData->m_topOrigin.release()); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerGlobalScope->script()->forbidExecution(); } } WorkerScriptController* script = m_workerGlobalScope->script(); #if ENABLE(INSPECTOR) InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), m_startupData->m_startMode); #endif script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData.clear(); runEventLoop(); ThreadIdentifier threadID = m_threadID; ASSERT(m_workerGlobalScope->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerGlobalScope = 0; // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! threadGlobalData().destroy(); // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); }
void* LocalStorageThread::localStorageThread() { while (true) { RefPtr<LocalStorageTask> task; if (!m_queue.waitForMessage(task)) break; task->performTask(); } // Detach the thread so its resources are no longer of any concern to anyone else detachThread(m_threadID); m_threadID = 0; // Clear the self refptr, possibly resulting in deletion m_selfRef = 0; return 0; }
static void* startThreadEntryPoint(void* _args) { ThreadEntryPointArgs* args = (ThreadEntryPointArgs*) _args; Env* env = args->env; Thread* thread = args->thread; JavaThread* threadObj = args->threadObj; rvmLockThreadsList(); jboolean failure = TRUE; setThreadEnv(env); if (!rvmExceptionOccurred(env)) { if (initThread(env, thread, threadObj)) { if (rvmSetupSignals(env)) { failure = FALSE; thread->stackAddr = getStackAddress(); } } } thread->status = THREAD_STARTING; pthread_cond_broadcast(&threadStartCond); while (thread->status != THREAD_VMWAIT) { pthread_cond_wait(&threadStartCond, &threadsLock); } rvmUnlockThreadsList(); if (!failure) { rvmChangeThreadStatus(env, thread, THREAD_RUNNING); rvmChangeThreadPriority(env, thread, thread->threadObj->priority); Method* run = rvmGetInstanceMethod2(env, java_lang_Thread, "run", "()V"); if (run) { jvalue emptyArgs[0]; rvmCallVoidInstanceMethodA(env, (Object*) threadObj, run, emptyArgs); } } detachThread(env, TRUE); return NULL; }
void* DatabaseThread::databaseThread() { { // Wait for DatabaseThread::start() to complete. MutexLocker lock(m_threadCreationMutex); LOG(StorageAPI, "Started DatabaseThread %p", this); } AutodrainedPool pool; while (true) { RefPtr<DatabaseTask> task; if (!m_queue.waitForMessage(task)) break; task->performTask(); pool.cycle(); } LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); // Close the databases that we ran transactions on. This ensures that if any transactions are still open, they are rolled back and we don't leave the database in an // inconsistent or locked state. if (m_openDatabaseSet.size() > 0) { // As the call to close will modify the original set, we must take a copy to iterate over. DatabaseSet openSetCopy; openSetCopy.swap(m_openDatabaseSet); DatabaseSet::iterator end = openSetCopy.end(); for (DatabaseSet::iterator it = openSetCopy.begin(); it != end; ++it) (*it)->close(); } // Detach the thread so its resources are no longer of any concern to anyone else detachThread(m_threadID); // Clear the self refptr, possibly resulting in deletion m_selfRef = 0; return 0; }
void FileThread::runLoop() { { // Wait for FileThread::start() to complete to have m_threadID // established before starting the main loop. MutexLocker lock(m_threadCreationMutex); LOG(FileAPI, "Started FileThread %p", this); } while (OwnPtr<Task> task = m_queue.waitForMessage()) { AutodrainedPool pool; task->performTask(); } LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); detachThread(m_threadID); // Clear the self refptr, possibly resulting in deletion m_selfRef = 0; }
void DownloadFileTransferAPI::threadFct(boost::shared_array<uint8_t> const &adata, size_t &size) { FBLOG_DEBUG("DownloadFileTransferAPI::threadFct", "this=" << this); mFileStream.open(mFileStr.c_str(), std::ios_base::out | std::ios_base::binary); if(mFileStream.fail()) { FBLOG_DEBUG("UploadFileTransferAPI::start", "Can't open the target file: " << mFileStr); onError("Can't open the target file"); return; } try { // Write the file by chunck const char *data = (const char *)adata.get(); size_t writeSize; while(!boost::this_thread::interruption_requested() && size > 0) { writeSize = size; if(writeSize > BUFFER_SIZE) writeSize = BUFFER_SIZE; mFileStream.write(data, writeSize); if(mFileStream.fail()) { FBLOG_DEBUG("DownloadFileTransferAPI::threadFct", "File write error"); onError("File write error"); throw std::runtime_error("File write error"); } data += writeSize; size -= writeSize; } mFileStream.close(); onSuccess(true); } catch(std::runtime_error&) { // Remove incomplete file mFileStream.close(); boost::filesystem::remove(mFilePath); } detachThread(boost::this_thread::get_id()); mThread.reset(); }
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) { JUCE_AUTORELEASEPOOL checkThreadIsAttached(); bool ok = true; while (numSamples > 0) { if (lastSampleRead != startSampleInFile) { TimeRecord time; time.scale = (TimeScale) inputStreamDesc.mSampleRate; time.base = 0; time.value.hi = 0; time.value.lo = (UInt32) startSampleInFile; OSStatus err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Movie, kQTMovieAudioExtractionMoviePropertyID_CurrentTime, sizeof (time), &time); if (err != noErr) { ok = false; break; } } int framesToDo = jmin (numSamples, (int) (bufferList->mBuffers[0].mDataByteSize / inputStreamDesc.mBytesPerFrame)); bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * framesToDo; UInt32 outFlags = 0; UInt32 actualNumFrames = framesToDo; OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumFrames, bufferList, &outFlags); if (err != noErr) { ok = false; break; } lastSampleRead = startSampleInFile + actualNumFrames; const int samplesReceived = actualNumFrames; for (int j = numDestChannels; --j >= 0;) { if (destSamples[j] != nullptr) { const short* src = ((const short*) bufferList->mBuffers[0].mData) + j; for (int i = 0; i < samplesReceived; ++i) { destSamples[j][startOffsetInDestBuffer + i] = (*src << 16); src += numChannels; } } } startOffsetInDestBuffer += samplesReceived; startSampleInFile += samplesReceived; numSamples -= samplesReceived; if (((outFlags & kQTMovieAudioExtractionComplete) != 0 || samplesReceived == 0) && numSamples > 0) { for (int j = numDestChannels; --j >= 0;) if (destSamples[j] != nullptr) zeromem (destSamples[j] + startOffsetInDestBuffer, sizeof (int) * numSamples); break; } } detachThread(); return ok; }
jint rvmDetachCurrentThread(VM* vm, jboolean ignoreAttachCount) { Env* env = rvmGetEnv(); if (!env) return JNI_EDETACHED; return detachThread(env, ignoreAttachCount); }
QTAudioReader (InputStream* const input_, const int trackNum_) : AudioFormatReader (input_, TRANS (quickTimeFormatName)), ok (false), movie (0), trackNum (trackNum_), lastSampleRead (0), lastThreadId (0), extractor (0), dataHandle (0) { JUCE_AUTORELEASEPOOL bufferList.calloc (256, 1); #if JUCE_WINDOWS if (InitializeQTML (0) != noErr) return; #endif if (EnterMovies() != noErr) return; bool opened = juce_OpenQuickTimeMovieFromStream (input_, movie, dataHandle); if (! opened) return; { const int numTracks = GetMovieTrackCount (movie); int trackCount = 0; for (int i = 1; i <= numTracks; ++i) { track = GetMovieIndTrack (movie, i); media = GetTrackMedia (track); OSType mediaType; GetMediaHandlerDescription (media, &mediaType, 0, 0); if (mediaType == SoundMediaType && trackCount++ == trackNum_) { ok = true; break; } } } if (! ok) return; ok = false; lengthInSamples = GetMediaDecodeDuration (media); usesFloatingPointData = false; samplesPerFrame = (int) (GetMediaDecodeDuration (media) / GetMediaSampleCount (media)); trackUnitsPerFrame = GetMovieTimeScale (movie) * samplesPerFrame / GetMediaTimeScale (media); OSStatus err = MovieAudioExtractionBegin (movie, 0, &extractor); unsigned long output_layout_size; err = MovieAudioExtractionGetPropertyInfo (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, 0, &output_layout_size, 0); if (err != noErr) return; HeapBlock <AudioChannelLayout> qt_audio_channel_layout; qt_audio_channel_layout.calloc (output_layout_size, 1); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout, 0); qt_audio_channel_layout[0].mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof (inputStreamDesc), &inputStreamDesc, 0); if (err != noErr) return; inputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian; inputStreamDesc.mBitsPerChannel = sizeof (SInt16) * 8; inputStreamDesc.mChannelsPerFrame = jmin ((UInt32) 2, inputStreamDesc.mChannelsPerFrame); inputStreamDesc.mBytesPerFrame = sizeof (SInt16) * inputStreamDesc.mChannelsPerFrame; inputStreamDesc.mBytesPerPacket = inputStreamDesc.mBytesPerFrame; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof (inputStreamDesc), &inputStreamDesc); if (err != noErr) return; Boolean allChannelsDiscrete = false; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Movie, kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, sizeof (allChannelsDiscrete), &allChannelsDiscrete); if (err != noErr) return; bufferList->mNumberBuffers = 1; bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame; bufferList->mBuffers[0].mDataByteSize = jmax ((UInt32) 4096, (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16); dataBuffer.malloc (bufferList->mBuffers[0].mDataByteSize); bufferList->mBuffers[0].mData = dataBuffer; sampleRate = inputStreamDesc.mSampleRate; bitsPerSample = 16; numChannels = inputStreamDesc.mChannelsPerFrame; detachThread(); ok = true; }
void detachJNIThread(Thread *thread) { /* The JNI spec says we should release all locks held by this thread. We don't do this (yet), and only remove the thread from the VM. */ detachThread(thread); }
void SteamCallbackAdapter::attach(SteamInvokeCallbackFunction fn) const { JNIEnv* env = attachThread(); fn(env); detachThread(); }
void AutomaticThread::start(const LockHolder&) { RELEASE_ASSERT(m_isRunning); RefPtr<AutomaticThread> preserveThisForThread = this; m_hasUnderlyingThread = true; ThreadIdentifier thread = createThread( "WTF::AutomaticThread", [=] () { if (verbose) dataLog(RawPointer(this), ": Running automatic thread!\n"); RefPtr<AutomaticThread> thread = preserveThisForThread; thread->threadDidStart(); if (!ASSERT_DISABLED) { LockHolder locker(*m_lock); ASSERT(m_condition->contains(locker, this)); } auto stopImpl = [&] (const LockHolder& locker) { thread->threadIsStopping(locker); thread->m_hasUnderlyingThread = false; }; auto stopPermanently = [&] (const LockHolder& locker) { m_isRunning = false; m_isRunningCondition.notifyAll(); stopImpl(locker); }; auto stopForTimeout = [&] (const LockHolder& locker) { stopImpl(locker); }; for (;;) { { LockHolder locker(*m_lock); for (;;) { PollResult result = poll(locker); if (result == PollResult::Work) break; if (result == PollResult::Stop) return stopPermanently(locker); RELEASE_ASSERT(result == PollResult::Wait); // Shut the thread down after one second. m_isWaiting = true; bool awokenByNotify = m_waitCondition.waitFor(*m_lock, 1_s); if (verbose && !awokenByNotify && !m_isWaiting) dataLog(RawPointer(this), ": waitFor timed out, but notified via m_isWaiting flag!\n"); if (m_isWaiting) { m_isWaiting = false; if (verbose) dataLog(RawPointer(this), ": Going to sleep!\n"); // It's important that we don't release the lock until we have completely // indicated that the thread is kaput. Otherwise we'll have a a notify // race that manifests as a deadlock on VM shutdown. return stopForTimeout(locker); } } } WorkResult result = work(); if (result == WorkResult::Stop) { LockHolder locker(*m_lock); return stopPermanently(locker); } RELEASE_ASSERT(result == WorkResult::Continue); } }); detachThread(thread); }