void FastSpinlock::EnterReadLock() { if (mLockOrder != LO_DONT_CARE) LLockOrderChecker->Push(this); while (true) { /// 다른놈이 writelock 풀어줄때까지 기다린다. while (mLockFlag & LF_WRITE_MASK) YieldProcessor(); //TODO: Readlock 진입 구현 (mLockFlag를 어떻게 처리하면 되는지?) // if ( readlock을 얻으면 ) //return; // else // mLockFlag 원복 if ( ( InterlockedAdd( &mLockFlag, 1 ) & LF_WRITE_MASK ) != LF_WRITE_FLAG ) { return; } else { InterlockedAdd( &mLockFlag, -1 ); } } }
void FastSpinlock::EnterWriteLock() { /// 락 순서 신경 안써도 되는 경우는 그냥 패스 if ( mLockOrder != LO_DONT_CARE) LLockOrderChecker->Push(this); while (true) { /// 다른놈이 writelock 풀어줄때까지 기다린다. while (mLockFlag & LF_WRITE_MASK) YieldProcessor(); if ((InterlockedAdd(&mLockFlag, LF_WRITE_FLAG) & LF_WRITE_MASK) == LF_WRITE_FLAG) { /// 다른놈이 readlock 풀어줄때까지 기다린다. while (mLockFlag & LF_READ_MASK) YieldProcessor(); return; } InterlockedAdd(&mLockFlag, -LF_WRITE_FLAG); } }
static void threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs) { MonoObject *ar; gint i; if (mono_runtime_is_shutting_down ()) return; if (tp->pool_status == 0 && InterlockedCompareExchange (&tp->pool_status, 1, 0) == 0) { if (!tp->is_io) { monitor_internal_thread = mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK); monitor_internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE; threadpool_start_thread (tp); } /* Create on demand up to min_threads to avoid startup penalty for apps that don't use * the threadpool that much */ if (mono_config_is_server_mode ()) { mono_thread_create_internal (mono_get_root_domain (), threadpool_start_idle_threads, tp, TRUE, SMALL_STACK); } } InterlockedAdd (&monitor_njobs, njobs); if (monitor_state == MONITOR_STATE_SLEEPING && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_SLEEPING) == MONITOR_STATE_SLEEPING) MONO_SEM_POST (&monitor_sem); if (monitor_state == MONITOR_STATE_FALLING_ASLEEP) InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_FALLING_ASLEEP); for (i = 0; i < njobs; i++) { ar = jobs [i]; if (ar == NULL || mono_domain_is_unloading (ar->vtable->domain)) continue; /* Might happen when cleaning domain jobs */ threadpool_jobs_inc (ar); #ifndef DISABLE_PERFCOUNTERS mono_perfcounter_update_value (tp->pc_nitems, TRUE, 1); #endif if (!tp->is_io && mono_wsq_local_push (ar)) continue; mono_cq_enqueue (tp->queue, ar); } #if DEBUG InterlockedAdd (&tp->njobs, njobs); #endif for (i = 0; tp->waiting > 0 && i < MIN(njobs, tp->max_threads); i++) pulse_on_new_job (tp); }
inline void ATOMIC_SUB(ATOMIC_T *v, int i) { #ifdef PLATFORM_LINUX atomic_sub(i,v); #elif defined(PLATFORM_WINDOWS) InterlockedAdd(v,-i); #endif }
inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i) { #ifdef PLATFORM_LINUX return atomic_sub_return(i,v); #elif defined(PLATFORM_WINDOWS) return InterlockedAdd(v,-i); #endif }
void FastSpinlock::LeaveWriteLock() { /// 락 순서 신경 안써도 되는 경우는 그냥 패스 if ( mLockOrder != LO_DONT_CARE ) LLockOrderChecker->Pop( this ); InterlockedAdd(&mLockFlag, -LF_WRITE_FLAG); }
void FastSpinlock::LeaveReadLock() { if ( mLockOrder != LO_DONT_CARE ) LLockOrderChecker->Pop( this ); //TODO: mLockFlag 처리 InterlockedAdd( &mLockFlag, -1 ); }
void account_mem (MonoMemAccountType type, ssize_t size) { #if SIZEOF_VOID_P == 4 InterlockedAdd ((volatile gint32*)&allocation_count [type], (gint32)size); #else InterlockedAdd64 ((volatile gint64*)&allocation_count [type], (gint64)size); #endif }
VOID SxLibCompletedInjectedNetBufferLists( _In_ PSX_SWITCH_OBJECT Switch, _In_ ULONG NumInjectedNetBufferLists ) { LONG subtract = -(LONG)NumInjectedNetBufferLists; InterlockedAdd(&Switch->PendingInjectedNblCount, subtract); }
inline void ATOMIC_ADD(ATOMIC_T *v, int i) { #ifdef PLATFORM_LINUX atomic_add(i,v); #elif defined(PLATFORM_WINDOWS) InterlockedAdd(v,i); #elif defined(PLATFORM_FREEBSD) atomic_add_int(v,i); #endif }
DWORD WINAPI thread_proc(LPVOID lpThreadParameter) { unsigned y0, y1; unsigned ASX = align(SX); while (TRUE) { y0 = (unsigned)InterlockedAdd(¤t_y, n_lines) - n_lines; if (y0 >= SY) return 0; y1 = min(y0 + n_lines, SY); calculate_func(data + y0 * ASX, X0, Y0, scale, y0, ASX, y1); } }
inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i) { #ifdef PLATFORM_LINUX return atomic_sub_return(i,v); #elif defined(PLATFORM_WINDOWS) return InterlockedAdd(v,-i); #elif defined(PLATFORM_FREEBSD) atomic_subtract_int(v,i); return atomic_load_acq_32(v); #endif }
inline gint iris_atomics_fetch_and_add (volatile void *ptr, gint add) { #if DARWIN return OSAtomicAdd32 (add, ptr); #elif WIN32 return InterlockedAdd (ptr, add) - add; #else return __sync_fetch_and_add ((gint*)ptr, add); #endif }
void FastSpinlock::EnterWriteLock() { while (true) { /// wait a writelock while (mLockFlag & LF_WRITE_MASK) YieldProcessor(); if ((InterlockedAdd(&mLockFlag, LF_WRITE_FLAG) & LF_WRITE_MASK) == LF_WRITE_FLAG) { /// wait a readlock while (mLockFlag & LF_READ_MASK) YieldProcessor(); return; } InterlockedAdd(&mLockFlag, -LF_WRITE_FLAG); } }
void RemoveAlloc(void* ptr, size_t size, long reqID) { InterlockedAdd(&g_globalTrackedMemory, -(intptr_t)(*g_memorySizes)[reqID]); // manual OutputDebugString with Windows' sprintf functions to avoid CRT deadlocks on the setlocale lock char buffer[8192]; wsprintfA(buffer, "%p/%d freed\n", ptr, reqID); OutputDebugStringA(buffer); EnterCriticalSection(&g_memCritSec); g_memorySizes->erase(reqID); g_newAllocations->erase(reqID); LeaveCriticalSection(&g_memCritSec); }
void StoreAlloc(void* ptr, size_t size, long reqID, const char* newFile, const char* newFunc, size_t newLine) { if (!g_memCritSec.DebugInfo) { g_memorySizes = new std::map<long, size_t>(); g_newAllocations = new std::set<long>(); InitializeCriticalSectionAndSpinCount(&g_memCritSec, 1000); } InterlockedAdd(&g_globalTrackedMemory, size); // manual OutputDebugString with Windows' sprintf functions to avoid CRT deadlocks on the setlocale lock char buffer[8192]; wsprintfA(buffer, "%s(%d) %s : allocating %d bytes (%d - %d used)\n", newFile, newLine, newFunc, size, reqID, g_globalTrackedMemory); OutputDebugStringA(buffer); EnterCriticalSection(&g_memCritSec); (*g_memorySizes)[reqID] = size; g_newAllocations->insert(reqID); if ((GetTickCount() - g_lastTrackTime) > 2500) { OutputDebugStringA("--- ALLOCATION HIT LIST ---\n"); for (auto& alloc : *g_newAllocations) { wsprintfA(buffer, "%d - %d\n", alloc, (*g_memorySizes)[alloc]); OutputDebugStringA(buffer); } wsprintfA(buffer, "--- TOTAL: %d ---\n", g_newAllocations->size()); OutputDebugStringA(buffer); g_newAllocations->clear(); g_lastTrackTime = GetTickCount(); } LeaveCriticalSection(&g_memCritSec); }
// Locks all other processors and returns exclusivity pointer. This function // should never be called before the last exclusivity is released. _Use_decl_annotations_ EXTERN_C void *ExclGainExclusivity() { NT_ASSERT(InterlockedAdd(&g_ExclpNumberOfLockedProcessors, 0) == 0); _InterlockedAnd(&g_ExclpReleaseAllProcessors, 0); const auto numberOfProcessors = KeQueryActiveProcessorCount(nullptr); // Allocates DPCs for all processors. auto context = reinterpret_cast<ExclusivityContext *>(ExAllocatePoolWithTag( NonPagedPoolNx, sizeof(void *) + (numberOfProcessors * sizeof(KDPC)), EXCLP_POOL_TAG)); if (!context) { return nullptr; } // Execute a lock DPC for all processors but this. context->OldIrql = KeRaiseIrqlToDpcLevel(); const auto currentCpu = KeGetCurrentProcessorNumber(); for (auto i = 0ul; i < numberOfProcessors; i++) { if (i == currentCpu) { continue; } // Queue a lock DPC. KeInitializeDpc(&context->Dpcs[i], ExclpRaiseIrqlAndWaitDpc, nullptr); KeSetTargetProcessorDpc(&context->Dpcs[i], static_cast<CCHAR>(i)); KeInsertQueueDpc(&context->Dpcs[i], nullptr, nullptr); } // Wait until all other processors were halted. const auto needToBeLocked = numberOfProcessors - 1; while (_InterlockedCompareExchange(&g_ExclpNumberOfLockedProcessors, needToBeLocked, needToBeLocked) != static_cast<LONG>(needToBeLocked)) { KeStallExecutionProcessor(10); } return context; }
void FastSpinlock::LeaveWriteLock() { InterlockedAdd(&mLockFlag, -LF_WRITE_FLAG); }
// // Routine Description: // // PL011pRxPioBufferCopy is called to copy new RX data from PIO RX buffer // to the caller RX buffer. // // Arguments: // // DevExtPtr - Our device context. // // BufferPtr - The caller buffer into which FIFO bytes should be // transferred. // // Length - Size in bytes of the caller buffer. // // Return Value: // // Number of bytes successfully written to caller buffer. // _Use_decl_annotations_ ULONG PL011pRxPioBufferCopy( PL011_DEVICE_EXTENSION* DevExtPtr, UCHAR* BufferPtr, ULONG Length ) { PL011_SERCXPIORECEIVE_CONTEXT* rxPioPtr = PL011SerCxPioReceiveGetContext(DevExtPtr->SerCx2PioReceive); // // Get number of bytes we can copy. // Is RX buffer empty ? // ULONG bytesToCopy = min(PL011pRxPendingByteCount(rxPioPtr), Length); if (bytesToCopy == 0) { return 0; } // // Copy RX data: RX Buffer -> Caller buffer // ULONG rxOut = rxPioPtr->RxBufferOut; ULONG bytesCopied = min(bytesToCopy, (PL011_RX_BUFFER_SIZE_BYTES - rxOut)); _Analysis_assume_(bytesCopied <= Length); RtlCopyMemory(BufferPtr, &rxPioPtr->RxBuffer[rxOut], bytesCopied); rxOut = (rxOut + bytesCopied) % PL011_RX_BUFFER_SIZE_BYTES; if (bytesCopied < bytesToCopy) { BufferPtr += bytesCopied; ULONG bytesLeftToCopy = bytesToCopy - bytesCopied; RtlCopyMemory(BufferPtr, &rxPioPtr->RxBuffer, bytesLeftToCopy); bytesCopied += bytesLeftToCopy; rxOut = bytesLeftToCopy; } // if (bytesCopied < bytesToCopy) rxPioPtr->RxBufferOut = rxOut; InterlockedAdd(&rxPioPtr->RxBufferCount, -LONG(bytesCopied)); if (bytesCopied != 0) { PL011_LOG_TRACE( "RX buffer: read %lu chars, buffer length %lu, in %lu, out %lu, count %lu", bytesCopied, Length, rxPioPtr->RxBufferIn, rxPioPtr->RxBufferOut, rxPioPtr->RxBufferCount ); } return bytesCopied; }
WindowsAtomics::Long WindowsAtomics::AtomicAdd( AtomicLong &Destination, Long Val) { return InterlockedAdd(&Destination, Val); }
VOID SxLibSendNetBufferListsIngress( _In_ PSX_SWITCH_OBJECT Switch, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ ULONG SendFlags, _In_ ULONG NumInjectedNetBufferLists ) { BOOLEAN dispatch; BOOLEAN sameSource; ULONG sendCompleteFlags; PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail; PNET_BUFFER_LIST curNbl, nextNbl; ULONG numNbls = 0; PNET_BUFFER_LIST dropNbl = NULL; PNET_BUFFER_LIST *curDropNbl = &dropNbl; NDIS_SWITCH_PORT_ID curSourcePort; NDIS_STRING filterReason; dispatch = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); sameSource = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_SWITCH_SINGLE_SOURCE); InterlockedAdd(&Switch->PendingInjectedNblCount, NumInjectedNetBufferLists); KeMemoryBarrier(); if (Switch->DataFlowState != SxSwitchRunning) { RtlInitUnicodeString(&filterReason, L"Extension Paused"); sendCompleteFlags = (dispatch) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0; sendCompleteFlags |= (sameSource) ? NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE : 0; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists); if (sameSource) { for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next) { ++numNbls; } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, fwdDetail->SourcePortId, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, NetBufferLists, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, NetBufferLists, sendCompleteFlags); } else { curSourcePort = fwdDetail->SourcePortId; for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl) { nextNbl = curNbl->Next; curNbl->Next = NULL; fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl); if(curSourcePort == fwdDetail->SourcePortId) { *curDropNbl = curNbl; curDropNbl = &(curNbl->Next); ++numNbls; } else { Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); numNbls = 1; dropNbl = curNbl; curDropNbl = &(curNbl->Next); curSourcePort = fwdDetail->SourcePortId; } } Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists( Switch->NdisSwitchContext, &SxExtensionGuid, &SxExtensionFriendlyName, curSourcePort, NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING, numNbls, dropNbl, &filterReason); SxExtStartCompleteNetBufferListsIngress(Switch, Switch->ExtensionContext, dropNbl, sendCompleteFlags); } goto Cleanup; } NdisFSendNetBufferLists(Switch->NdisFilterHandle, NetBufferLists, NDIS_DEFAULT_PORT_NUMBER, SendFlags); Cleanup: return; }
bool FFmpegDecoder::handleVideoPacket( const AVPacket& packet, double& videoClock, VideoParseContext& context) { enum { MAX_SKIPPED = 4 }; const double MAX_DELAY = 0.2; const int ret = avcodec_send_packet(m_videoCodecContext, &packet); if (ret < 0) return false; AVFramePtr videoFrame(av_frame_alloc()); while (avcodec_receive_frame(m_videoCodecContext, videoFrame.get()) == 0) { const int64_t duration_stamp = videoFrame->best_effort_timestamp; //av_frame_get_best_effort_timestamp(m_videoFrame); // compute the exact PTS for the picture if it is omitted in the stream // pts1 is the dts of the pkt / pts of the frame if (duration_stamp != AV_NOPTS_VALUE) { videoClock = duration_stamp * av_q2d(m_videoStream->time_base); } const double pts = videoClock; // update video clock for next frame // for MPEG2, the frame can be repeated, so we update the clock accordingly const double frameDelay = av_q2d(m_videoCodecContext->time_base) * (1. + videoFrame->repeat_pict * 0.5); videoClock += frameDelay; boost::posix_time::time_duration td(boost::posix_time::pos_infin); bool inNextFrame = false; const bool haveVideoPackets = !m_videoPacketsQueue.empty(); { boost::lock_guard<boost::mutex> locker(m_isPausedMutex); inNextFrame = m_isPaused && m_isVideoSeekingWhilePaused; if (!context.initialized || inNextFrame) { m_videoStartClock = (m_isPaused ? m_pauseTimer : GetHiResTime()) - pts; } // Skipping frames if (context.initialized && !inNextFrame && haveVideoPackets) { const double curTime = GetHiResTime(); if (m_videoStartClock + pts <= curTime) { if (m_videoStartClock + pts < curTime - MAX_DELAY) { InterlockedAdd(m_videoStartClock, MAX_DELAY); } if (++context.numSkipped > MAX_SKIPPED) { context.numSkipped = 0; } else { CHANNEL_LOG(ffmpeg_sync) << "Hard skip frame"; // pause if (m_isPaused && !m_isVideoSeekingWhilePaused) { break; } continue; } } else { int speedNumerator, speedDenominator; std::tie(speedNumerator, speedDenominator) = static_cast<const std::pair<int, int>&>(m_speedRational); context.numSkipped = 0; td = boost::posix_time::milliseconds( int((m_videoStartClock + pts - curTime) * 1000. * speedDenominator / speedNumerator) + 1); } } } context.initialized = true; { boost::unique_lock<boost::mutex> locker(m_videoFramesMutex); if (!m_videoFramesCV.timed_wait(locker, td, [this] { return m_isPaused && !m_isVideoSeekingWhilePaused || m_videoFramesQueue.canPush(); })) { continue; } } { boost::lock_guard<boost::mutex> locker(m_isPausedMutex); if (m_isPaused && !m_isVideoSeekingWhilePaused) { break; } m_isVideoSeekingWhilePaused = false; } if (inNextFrame) { m_isPausedCV.notify_all(); } VideoFrame& current_frame = m_videoFramesQueue.back(); handleDirect3dData(videoFrame.get()); if (!frameToImage(current_frame, videoFrame, m_imageCovertContext, m_pixelFormat)) { continue; } current_frame.m_pts = pts; current_frame.m_duration = duration_stamp; { boost::lock_guard<boost::mutex> locker(m_videoFramesMutex); m_videoFramesQueue.pushBack(); } m_videoFramesCV.notify_all(); } return true; }
_ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register uint32_t val) { return InterlockedAdd((LONG volatile *)pw, val); }
void atomicAdd(atomic* pAtomic, int value) { InterlockedAdd(pAtomic, value); }
void atomicSub(atomic* pAtomic, int value) { InterlockedAdd(pAtomic, -value); }
void FuncInterlock() { InterlockedAdd(&g_num, 2); }