Example #1
0
void OnCreatePool() {

   // Sanity checks
   if (g_pThreadPool != NULL) {
      OnDeletePool();
   }
   
   // Initialize the private thread pool
   g_pThreadPool = CreateThreadpool(NULL);
   if (g_pThreadPool == NULL) {
      MessageBox(
         NULL, 
         TEXT("Impossible to create private thread pool"), 
         TEXT("Initialization error"), 
         MB_ICONERROR | MB_OK
         );
      return;
   }

   // Change  min=2 / max=4 thread pool parameters
   SetThreadpoolThreadMaximum(g_pThreadPool, 4);
   if (!SetThreadpoolThreadMinimum(g_pThreadPool, 2)) {
      MessageBox(
         NULL, 
         TEXT("SetThreadpoolThreadMinimum failed."), 
         TEXT("Initialization error"), 
         MB_ICONERROR | MB_OK
         );
      return;
   }

   // Reset the callback environment
   // Note: this is an inline function from winbase.h
   //       that calls TpInitializeCallbackEnviron() in winnt.h.
   //       --> 
   //       CallbackEnviron->Version = 1;
   //       CallbackEnviron->Pool = NULL;
   //       CallbackEnviron->CleanupGroup = NULL;
   //       CallbackEnviron->CleanupGroupCancelCallback = NULL;
   //       CallbackEnviron->RaceDll = NULL;
   //       CallbackEnviron->ActivationContext = NULL;
   //       CallbackEnviron->FinalizationCallback = NULL;
   //       CallbackEnviron->u.Flags = 0;
   InitializeThreadpoolEnvironment(&g_callbackEnvironment);

   // Associate our private thread pool with the callback environment
   // Note: this is an inline function from winbase.h
   //       that calls TpSetCallbackThreadpool() in winnt.h.
   //       --> 
   //       CallbackEnviron->Pool = Pool;
   SetThreadpoolCallbackPool(&g_callbackEnvironment, g_pThreadPool);  
}
Example #2
0
int TestPoolThread(int argc, char* argv[])
{
	TP_POOL* pool;

	pool = CreateThreadpool(NULL);

	SetThreadpoolThreadMinimum(pool, 8); /* default is 0 */
	SetThreadpoolThreadMaximum(pool, 64); /* default is 500 */

	CloseThreadpool(pool);

	return 0;
}
Example #3
0
void CThreadPools::CreateThreadPools(int nThreadCount)
{
	BOOL bRet = FALSE;

	InitializeThreadpoolEnvironment(&m_CallBackEnviron);

	// Create a custom, dedicated thread pool
	m_pPool = CreateThreadpool(NULL);

	if (NULL==m_pPool) 
	{
		CloseThreadPools();
	}

	m_nRollback = 1; // pool creation succeeded

	// The thread pool is made persistent simply by setting
	// both the minimum and maximum threads to 1.
	SetThreadpoolThreadMaximum(m_pPool, nThreadCount);

	bRet = SetThreadpoolThreadMinimum(m_pPool, 1);

	if (FALSE==bRet) 
	{
		CloseThreadPools();
	}

	//Create a cleanup group for this thread pool
	m_pCleanupGroup = CreateThreadpoolCleanupGroup();

	if (NULL==m_pCleanupGroup) 
	{
		CloseThreadPools(); 
	}

	m_nRollback = 2;  // Cleanup group creation succeeded

	// Associate the callback environment with our thread pool.
	SetThreadpoolCallbackPool(&m_CallBackEnviron, m_pPool);

	// Associate the cleanup group with our thread pool.
	// Objects created with the same callback environment
	// as the cleanup group become members of the cleanup group.
	SetThreadpoolCallbackCleanupGroup(&m_CallBackEnviron, m_pCleanupGroup, NULL);

	m_nRollback = 3;  // Creation of work succeeded

}
Example #4
0
BOOL CTreadPool::Create( int nMaxThreads, int nMinThreads )
{
	m_pPool = CreateThreadpool(NULL);
	if (m_pPool==NULL)
	{
		OutputDebugString(TEXT("Create Thread Pool failed \n"));
		return FALSE;
	}

	m_nMinThreads = nMinThreads;
	m_nMaxThreads = nMaxThreads;

	SetThreadpoolThreadMaximum(m_pPool, nMaxThreads);
	SetThreadpoolThreadMinimum(m_pPool, nMinThreads);

	m_pTp_callback_environ = new TP_CALLBACK_ENVIRON;
	InitializeThreadpoolEnvironment(m_pTp_callback_environ);

	SetThreadpoolCallbackPool(m_pTp_callback_environ, m_pPool);

	return TRUE;
}
Example #5
0
__declspec(noinline) bool benchmark_ntp_fs_stat() {
	TP_CALLBACK_ENVIRON env;
	InitializeThreadpoolEnvironment(&env);

	PTP_POOL pool{nullptr};
	pool = CreateThreadpool(nullptr);
	SetThreadpoolThreadMaximum(pool, 48);
	SetThreadpoolThreadMinimum(pool, 12);

	PTP_CLEANUP_GROUP group = CreateThreadpoolCleanupGroup();
	SetThreadpoolCallbackPool(&env, pool);
	SetThreadpoolCallbackCleanupGroup(&env, group, nullptr);

	PTP_WORK work_fs_stat = CreateThreadpoolWork(WorkCallback_fs_stat, nullptr, &env);


	SubmitThreadpoolWork(work_fs_stat);
	WaitForThreadpoolWorkCallbacks(work_fs_stat, false);

	CloseThreadpoolWork(work_fs_stat);

	CloseThreadpool(pool);
	return false;
}
HRESULT
FxInterruptThreadpool::Initialize(
    )
{
    HRESULT hr = S_OK;
    DWORD error;
    BOOL bRet;

    //
    // Create a thread pool using win32 APIs
    //
    m_Pool = CreateThreadpool(NULL);
    if (m_Pool == NULL) 
    {
        error = GetLastError();
        hr = HRESULT_FROM_WIN32(error);
        DoTraceLevelMessage(GetDriverGlobals(), 
                    TRACE_LEVEL_ERROR, TRACINGPNP,
                    "Threadpool creation failed, %!winerr!", error);           
        return hr;
    }

    //
    // Set maximum thread count to equal the total number of interrupts.
    // Set minimum thread count (persistent threads) to equal the lower of 
    // number of interrupt and number of processors. 
    // 
    // We want minimum number of persistent threads to be at least equal to the 
    // number of interrupt objects so that there is no delay in servicing the
    // interrupt if there are processors available (the delay can come due to 
    // thread pool delay in allocating and initializing a new thread). However,
    // there is not much benefit in having more persistent threads than 
    // processors, as threads would have to wait for processor to become 
    // available anyways. Therefore, we chose to have the number of persistent 
    // equal to the Min(number of interrupts, number of processors). 
    // 
    // In the current design, if there are more interrupts than 
    // processors, as soon as one thread finishes servicing the interrupt, both 
    // the thread and processor will be available to service the next queued 
    // interrupt. Note that thread pool will queue all the waits and will 
    // satisfy them in a FIFO manner. 
    //
    // Since we don't know the number of interrupts in the beginning, we will 
    // start with one and update it when we know the actual number of interrupts
    // after processing driver's OnPrepareHardware callback.
    //
    // Note on interrupt servicing:
    // When fx connects the interrupt, it queues an event-based wait block 
    // to thread pool for each interrupt, so that the interrupt can get serviced 
    // using one of the thread pool threads when the auto-reset event shared 
    // with reflector is set by reflector in the DpcForIsr routine queued by Isr. 
    // While the interrupt is being serviced by one of the threads, no wait block
    // is queued to thread pool for that interrupt, so arrival of same interrupt
    // signals the event in DpcForIsr but doesn't cause new threads to pick up 
    // the servicing. Note that other interrupts still have their wait blocks
    // queued so they will be serviced as they arrive.
    // 
    // When previous servicing is over (i.e. the ISR callback has been 
    // invoked and it has returned), Fx queues another wait block to thread pool
    // for that interrupt. If the event is already signalled, it would result in
    // the same thread (or another) picking up servicing immediately. 
    //
    // This means the interrupt ISR routine can never run concurrently 
    // for same interrupt. Therefore, there is no need to have more than one 
    // thread for each interrupt.   
    //
    SetThreadpoolThreadMaximum(m_Pool, 1);

    //
    // Create one persistent thread since atleast one interrupt is the most 
    // likely scenario. We will update this number to have either the same
    // number of threads as there are interrupts, or the number of 
    // processors on the machine.
    //
    bRet = SetThreadpoolThreadMinimum(m_Pool, m_MinimumThreadCount);
    if (bRet == FALSE) {
        error = GetLastError();
        hr = HRESULT_FROM_WIN32(error);
        DoTraceLevelMessage(GetDriverGlobals(), 
                    TRACE_LEVEL_ERROR, TRACINGPNP,
                    "%!FUNC!: Failed to set minimum threads (%d) in threadpool,"
                    " %!winerr!", m_MinimumThreadCount, error);           
        goto cleanup;
    }

    //
    // Associate thread pool with callback environment.
    //
    SetThreadpoolCallbackPool(&m_CallbackEnvironment, m_Pool);          
   
cleanup:

    if (FAILED(hr)) {
        CloseThreadpool(m_Pool);
        m_Pool = NULL;
    }

    return hr;
}
HRESULT
FxInterruptThreadpool::UpdateThreadPoolThreadLimits(
    _In_ ULONG InterruptCount
    )
{
    BOOL bRet;
    HRESULT hr = S_OK;
    SYSTEM_INFO sysInfo;
    ULONG minThreadCount = 0;
    ULONG procs;
    DWORD error;
    
    FX_VERIFY(INTERNAL, CHECK_NOT_NULL(m_Pool));

    //
    // if there are more than one interrupts then we need to update minimum
    // thread count. 
    //
    if (m_MinimumThreadCount >= InterruptCount) {
        //
        // nothing to do 
        //
        return S_OK;
    }

    //
    // We want to have number of minimum persistent threads 
    // = Min(number of interrupts, number of processors). 
    // See comments in Initialize routine for details. 
    //
    GetSystemInfo(&sysInfo); 
    procs = sysInfo.dwNumberOfProcessors;

    minThreadCount = min(InterruptCount, procs);

    if (m_MinimumThreadCount < minThreadCount) {
        //
        // Set threadpool min  
        //
        bRet = SetThreadpoolThreadMinimum(m_Pool, minThreadCount);
        if (bRet == FALSE) {
            error = GetLastError();
            hr = HRESULT_FROM_WIN32(error);
            DoTraceLevelMessage(GetDriverGlobals(), 
                        TRACE_LEVEL_ERROR, TRACINGPNP,
                        "Failed to set minimum threads in threadpool,"
                        " TP_POOL 0x%p to %d %!winerr!", m_Pool, minThreadCount, 
                        error);           
            return hr;
        }
        
        m_MinimumThreadCount = minThreadCount;
    }

    //
    // set thread pool max to max number of interrupts 
    //
    SetThreadpoolThreadMaximum(m_Pool, InterruptCount);
    
    DoTraceLevelMessage(GetDriverGlobals(), 
                TRACE_LEVEL_ERROR, TRACINGPNP,
                "Threads in thread pool TP_POOL 0x%p updated" 
                " to Max %d Min %d threads", m_Pool, 
                InterruptCount, minThreadCount);

    return hr;
}
Example #8
0
RFX_CONTEXT* rfx_context_new(void)
{
	HKEY hKey;
	LONG status;
	DWORD dwType;
	DWORD dwSize;
	DWORD dwValue;
	SYSTEM_INFO sysinfo;
	RFX_CONTEXT* context;

	context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT));
	ZeroMemory(context, sizeof(RFX_CONTEXT));

	context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV));
	ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV));

	context->priv->TilePool = Queue_New(TRUE, -1, -1);
	context->priv->TileQueue = Queue_New(TRUE, -1, -1);

	/*
	 * align buffers to 16 byte boundary (needed for SSE/NEON instructions)
	 *
	 * y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * 4 = 16384 (0x4000)
	 * dwt_buffer: 32 * 32 * 2 * 2 * 4 = 16384, maximum sub-band width is 32
	 */

	context->priv->BufferPool = BufferPool_New(TRUE, 16384, 16);

#ifdef _WIN32
	{
		BOOL isVistaOrLater;
		OSVERSIONINFOA verinfo;

		ZeroMemory(&verinfo, sizeof(OSVERSIONINFOA));
		verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);

		GetVersionExA(&verinfo);
		isVistaOrLater = ((verinfo.dwMajorVersion >= 6) && (verinfo.dwMinorVersion >= 0)) ? TRUE : FALSE;

		context->priv->UseThreads = isVistaOrLater;
	}
#else
	context->priv->UseThreads = TRUE;
#endif

	GetNativeSystemInfo(&sysinfo);

	context->priv->MinThreadCount = sysinfo.dwNumberOfProcessors;
	context->priv->MaxThreadCount = 0;

	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\RemoteFX"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);

	if (status == ERROR_SUCCESS)
	{
		if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			context->priv->UseThreads = dwValue ? 1 : 0;

		if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			context->priv->MinThreadCount = dwValue;

		if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			context->priv->MaxThreadCount = dwValue;

		RegCloseKey(hKey);
	}

	if (context->priv->UseThreads)
	{
		/* Call primitives_get here in order to avoid race conditions when using primitives_get */
		/* from multiple threads. This call will initialize all function pointers correctly     */
		/* before any decoding threads are started */
		primitives_get();

		context->priv->ThreadPool = CreateThreadpool(NULL);
		InitializeThreadpoolEnvironment(&context->priv->ThreadPoolEnv);
		SetThreadpoolCallbackPool(&context->priv->ThreadPoolEnv, context->priv->ThreadPool);

		if (context->priv->MinThreadCount)
			SetThreadpoolThreadMinimum(context->priv->ThreadPool, context->priv->MinThreadCount);

		if (context->priv->MaxThreadCount)
			SetThreadpoolThreadMaximum(context->priv->ThreadPool, context->priv->MaxThreadCount);
	}

	/* initialize the default pixel format */
	rfx_context_set_pixel_format(context, RDP_PIXEL_FORMAT_B8G8R8A8);

	/* create profilers for default decoding routines */
	rfx_profiler_create(context);
	
	/* set up default routines */
	context->quantization_decode = rfx_quantization_decode;	
	context->quantization_encode = rfx_quantization_encode;	
	context->dwt_2d_decode = rfx_dwt_2d_decode;
	context->dwt_2d_encode = rfx_dwt_2d_encode;

	RFX_INIT_SIMD(context);
	
	return context;
}
Example #9
0
int TestPoolWork(int argc, char* argv[])
{
	int index;
	PTP_POOL pool;
	PTP_WORK work;
	PTP_CLEANUP_GROUP cleanupGroup;
	TP_CALLBACK_ENVIRON environment;

	printf("Global Thread Pool\n");

	work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", NULL);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		return -1;
	}

	/**
	 * You can post a work object one or more times (up to MAXULONG) without waiting for prior callbacks to complete.
	 * The callbacks will execute in parallel. To improve efficiency, the thread pool may throttle the threads.
	 */

	for (index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);
	CloseThreadpoolWork(work);

	printf("Private Thread Pool\n");

	if (!(pool = CreateThreadpool(NULL)))
	{
		printf("CreateThreadpool failure\n");
		return -1;
	}

	if (!SetThreadpoolThreadMinimum(pool, 4))
	{
		printf("SetThreadpoolThreadMinimum failure\n");
		return -1;
	}

	SetThreadpoolThreadMaximum(pool, 8);

	InitializeThreadpoolEnvironment(&environment);
	SetThreadpoolCallbackPool(&environment, pool);

	cleanupGroup = CreateThreadpoolCleanupGroup();

	if (!cleanupGroup)
	{
		printf("CreateThreadpoolCleanupGroup failure\n");
		return -1;
	}

	SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, NULL);

	work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", &environment);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		return -1;
	}

	for (index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);

	CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, NULL);

	CloseThreadpoolCleanupGroup(cleanupGroup);

	DestroyThreadpoolEnvironment(&environment);

	/**
	 * See Remarks at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682043(v=vs.85).aspx
	 * If there is a cleanup group associated with the work object,
	 * it is not necessary to call CloseThreadpoolWork !
	 * calling the CloseThreadpoolCleanupGroupMembers function releases the work, wait,
	 * and timer objects associated with the cleanup group.
	 */

	/* CloseThreadpoolWork(work); // this would segfault, see comment above. */

	CloseThreadpool(pool);

	return 0;
}
Example #10
0
File: rfx.c Project: C4rt/FreeRDP
RFX_CONTEXT* rfx_context_new(BOOL encoder)
{
	HKEY hKey;
	LONG status;
	DWORD dwType;
	DWORD dwSize;
	DWORD dwValue;
	SYSTEM_INFO sysinfo;
	RFX_CONTEXT* context;
	wObject *pool;
	RFX_CONTEXT_PRIV *priv;

	context = (RFX_CONTEXT*)calloc(1, sizeof(RFX_CONTEXT));
	if (!context)
		return NULL;

	context->encoder = encoder;
	context->priv = priv = (RFX_CONTEXT_PRIV *)calloc(1, sizeof(RFX_CONTEXT_PRIV) );
	if (!priv)
		goto error_priv;

	WLog_Init();

	priv->log = WLog_Get("com.freerdp.codec.rfx");
	WLog_OpenAppender(priv->log);

#ifdef WITH_DEBUG_RFX
	WLog_SetLogLevel(priv->log, WLOG_DEBUG);
#endif

	priv->TilePool = ObjectPool_New(TRUE);
	if (!priv->TilePool)
		goto error_tilePool;
	pool = ObjectPool_Object(priv->TilePool);
	pool->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init;

	if (context->encoder)
	{
		pool->fnObjectNew = (OBJECT_NEW_FN) rfx_encoder_tile_new;
		pool->fnObjectFree = (OBJECT_FREE_FN) rfx_encoder_tile_free;
	}
	else
	{
		pool->fnObjectNew = (OBJECT_NEW_FN) rfx_decoder_tile_new;
		pool->fnObjectFree = (OBJECT_FREE_FN) rfx_decoder_tile_free;
	}

	/*
	 * align buffers to 16 byte boundary (needed for SSE/NEON instructions)
	 *
	 * y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * sizeof(INT16) = 8192 (0x2000)
	 * dwt_buffer: 32 * 32 * 2 * 2 * sizeof(INT16) = 8192, maximum sub-band width is 32
	 *
	 * Additionally we add 32 bytes (16 in front and 16 at the back of the buffer)
	 * in order to allow optimized functions (SEE, NEON) to read from positions 
	 * that are actually in front/beyond the buffer. Offset calculations are
	 * performed at the BufferPool_Take function calls in rfx_encode/decode.c.
	 *
	 * We then multiply by 3 to use a single, partioned buffer for all 3 channels.
	 */

	priv->BufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16);
	if (!priv->BufferPool)
		goto error_BufferPool;

#ifdef _WIN32
	{
		BOOL isVistaOrLater;
		OSVERSIONINFOA verinfo;

		ZeroMemory(&verinfo, sizeof(OSVERSIONINFOA));
		verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);

		GetVersionExA(&verinfo);
		isVistaOrLater = ((verinfo.dwMajorVersion >= 6) && (verinfo.dwMinorVersion >= 0)) ? TRUE : FALSE;

		priv->UseThreads = isVistaOrLater;
	}
#else
	priv->UseThreads = TRUE;
#endif

	GetNativeSystemInfo(&sysinfo);

	priv->MinThreadCount = sysinfo.dwNumberOfProcessors;
	priv->MaxThreadCount = 0;

	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\RemoteFX"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);

	if (status == ERROR_SUCCESS)
	{
		dwSize = sizeof(dwValue);

		if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			priv->UseThreads = dwValue ? 1 : 0;

		if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			priv->MinThreadCount = dwValue;

		if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
			priv->MaxThreadCount = dwValue;

		RegCloseKey(hKey);
	}

	if (priv->UseThreads)
	{
		/* Call primitives_get here in order to avoid race conditions when using primitives_get */
		/* from multiple threads. This call will initialize all function pointers correctly     */
		/* before any decoding threads are started */
		primitives_get();

		priv->ThreadPool = CreateThreadpool(NULL);
		if (!priv->ThreadPool)
			goto error_threadPool;
		InitializeThreadpoolEnvironment(&priv->ThreadPoolEnv);
		SetThreadpoolCallbackPool(&priv->ThreadPoolEnv, priv->ThreadPool);

		if (priv->MinThreadCount)
			if (!SetThreadpoolThreadMinimum(priv->ThreadPool, priv->MinThreadCount))
				goto error_threadPool_minimum;

		if (priv->MaxThreadCount)
			SetThreadpoolThreadMaximum(priv->ThreadPool, priv->MaxThreadCount);
	}

	/* initialize the default pixel format */
	rfx_context_set_pixel_format(context, RDP_PIXEL_FORMAT_B8G8R8A8);

	/* create profilers for default decoding routines */
	rfx_profiler_create(context);
	
	/* set up default routines */
	context->quantization_decode = rfx_quantization_decode;	
	context->quantization_encode = rfx_quantization_encode;	
	context->dwt_2d_decode = rfx_dwt_2d_decode;
	context->dwt_2d_encode = rfx_dwt_2d_encode;

	RFX_INIT_SIMD(context);
	
	context->state = RFX_STATE_SEND_HEADERS;
	return context;

error_threadPool_minimum:
	CloseThreadpool(priv->ThreadPool);
error_threadPool:
	BufferPool_Free(priv->BufferPool);
error_BufferPool:
	ObjectPool_Free(priv->TilePool);
error_tilePool:
	free(priv);
error_priv:
	free(context);
	return NULL;
}
Example #11
0
int TestPoolWork(int argc, char* argv[])
{
	int index;
	PTP_POOL pool;
	PTP_WORK work;
	PTP_CLEANUP_GROUP cleanupGroup;
	TP_CALLBACK_ENVIRON environment;

	printf("Global Thread Pool\n");

	work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", NULL);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		return -1;
	}

	/**
	 * You can post a work object one or more times (up to MAXULONG) without waiting for prior callbacks to complete.
	 * The callbacks will execute in parallel. To improve efficiency, the thread pool may throttle the threads.
	 */

	for (index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);
	CloseThreadpoolWork(work);

	printf("Private Thread Pool\n");

	pool = CreateThreadpool(NULL);

	SetThreadpoolThreadMinimum(pool, 4);
	SetThreadpoolThreadMaximum(pool, 8);

	InitializeThreadpoolEnvironment(&environment);
	SetThreadpoolCallbackPool(&environment, pool);

	cleanupGroup = CreateThreadpoolCleanupGroup();

	if (!cleanupGroup)
	{
		printf("CreateThreadpoolCleanupGroup failure\n");
		return -1;
	}

	SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, NULL);

	work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", &environment);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		return -1;
	}

	for (index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);

	CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, NULL);

	CloseThreadpoolCleanupGroup(cleanupGroup);

	DestroyThreadpoolEnvironment(&environment);

	CloseThreadpoolWork(work);
	CloseThreadpool(pool);

	return 0;
}
Example #12
0
int _tmain1(int argc, _TCHAR* argv[])
{
    if (depth == 0) {
        Display("%d(%d)************\n", GetCurrentProcessId(), GetCurrentThreadId());
        return 1;
    }

    int multiply = 1;
    if (argc > 2) {
        multiply = _ttoi(argv[2]);
        if (multiply < 1) {
            Display("multiply should be greater than 1\n");
            return -2;
        }
    }

    TP_CALLBACK_ENVIRON CallBackEnviron;
    InitializeThreadpoolEnvironment(&CallBackEnviron);
    PTP_POOL pool = CreateThreadpool(NULL);
    if (NULL == pool) {
        _tprintf(_T("CreateThreadpool failed. LastError: %u\n"), GetLastError());
    }
    SetThreadpoolThreadMaximum(pool, 100);
    BOOL bRet = SetThreadpoolThreadMinimum(pool, 20);
    if (!bRet) {
        _tprintf(_T("SetThreadpoolThreadMinimum failed. LastError: %u\n"), GetLastError());
    }
    PTP_CLEANUP_GROUP cleanupgroup = CreateThreadpoolCleanupGroup();
    if (NULL == cleanupgroup) {
        _tprintf(_T("CreateThreadpoolCleanupGroup failed. LastError: %u\n"), GetLastError());
    }

    SetThreadpoolCallbackPool(&CallBackEnviron, pool);
    SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,
                                      cleanupgroup,
                                      NULL);

    struct ProcSetup {
        PROCESS_INFORMATION pi;
        HANDLE hEvent;
        HANDLE hWait;
        HANDLE hOutputRead;
        HANDLE hErrorRead;
        HANDLE hInputWrite;

        int rc;
        ProcSetup(PROCESS_INFORMATION _pi, HANDLE _hEvent, HANDLE _hWait,
                  HANDLE _hOutputRead, HANDLE _hErrorRead, HANDLE _hInputWrite)
            : pi(_pi), hEvent(_hEvent), hWait(_hWait), hOutputRead(_hOutputRead), hErrorRead(_hErrorRead), hInputWrite(_hInputWrite) {}
    };

    ProcSetup* pss = (ProcSetup*)calloc(multiply, sizeof(ProcSetup));

    for (int i = 0; i < multiply; i++) {
        Display("%d(%d) Multiply %d out of %d\n", GetCurrentProcessId(), GetCurrentThreadId(), i, multiply);
        HANDLE hOutputRead, hOutputWrite;
        HANDLE hErrorRead, hErrorWrite;
        HANDLE hInputRead, hInputWrite;
        SECURITY_ATTRIBUTES sa;

        // Set up the security attributes struct.
        sa.nLength= sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;

        STARTUPINFO startup_info;
        ZeroMemory(&startup_info, sizeof(startup_info));
        startup_info.cb = sizeof(startup_info);
        startup_info.dwFlags = STARTF_USESTDHANDLES;

        PROCESS_INFORMATION process_info;
        ZeroMemory(&process_info, sizeof(process_info));

        TCHAR cmd[1024];
        _stprintf(cmd, _T("%s %d"), argv[0], depth-1);
        BOOL result = CreateProcess(NULL,   // ApplicationName
                                    cmd,
                                    NULL,   // ProcessAttributes
                                    NULL,   // ThreadAttributes
                                    TRUE,   // InheritHandles
                                    CREATE_SUSPENDED, // | CREATE_BREAKAWAY_FROM_JOB,      // CreationFlags
                                    NULL,
                                    NULL,
                                    &startup_info,
                                    &process_info);
        pss[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        pss[i].pi = process_info;

        PTP_WAIT myWait = CreateThreadpoolWait(callback, new WaiterParams(process_info, pss[i].hEvent, &pss[i].rc), &CallBackEnviron);
        SetThreadpoolWait(myWait, process_info.hProcess, NULL);

        ResumeThread(process_info.hThread);

    }

    HANDLE* events = (HANDLE*)calloc(multiply, sizeof(HANDLE));
    for (int i = 0; i < multiply; i++) {
        events[i] = pss[i].hEvent;
    }
    WaitForMultipleObjects(multiply, events, true, INFINITE);

    int exit_code;
    for (int i = 0; i < multiply; i++) {
        PROCESS_INFORMATION* process_info = &pss[i].pi;

        int texit_code;
        BOOL ok = GetExitCodeThread(process_info->hThread,
                                    reinterpret_cast<DWORD*>(&texit_code));
        if (!ok) {
            printf("*** GetExitCodeThread failed %d\n", GetLastError());
        }
        ok = GetExitCodeProcess(process_info->hProcess,
                                reinterpret_cast<DWORD*>(&exit_code));
        if (!ok) {
            printf("*** GetExitCodeProcess failed %d\n", GetLastError());
        }
        if (texit_code != exit_code) {
            printf("*** Thread %d exit code %x didn't match process %d exit code %x\n", process_info->dwThreadId, texit_code, process_info->dwProcessId, exit_code);
        }
        CloseHandle(process_info->hProcess);
        CloseHandle(process_info->hThread);

//    *wp->pRC = exit_code;
//    exit_code = pss[i].rc;
        if (exit_code != 1) {
            printf("Failed to get correct exit code. Got %d instead\n", exit_code);
        }
    }
    for (int i = 0; i < multiply; i++) {
        CloseHandle(pss[i].hEvent);
    }
    free(events);

    CloseThreadpoolCleanupGroupMembers(cleanupgroup, FALSE, NULL);
    CloseThreadpoolCleanupGroup(cleanupgroup);
    CloseThreadpool(pool);
    DestroyThreadpoolEnvironment(&CallBackEnviron);

    return exit_code;
}