How to name a thread in Windows Performance Analyzer? - windows

I was trying to display the names of threads in Windows Performance Analyzer (WPA) (under Windows 8.1). This tool has a column called "thread name".
I followed the famous MSDN article:
http://msdn.microsoft.com/en-us/library/xcb2z8hs(v=vs.110).aspx
However, looks like it doesn't work in WPA. And according to a 3rd-party document, only Microsoft’s Visual Studio and WinDbg debuggers support this exception.
So how can I name a thread so that its name can be displayed in WPA?

Starting in Windows 10, version 1607, you can use the SetThreadDescription() API, which is now supported in xperf/WPA:
https://randomascii.wordpress.com/2015/10/26/thread-naming-in-windows-time-for-something-better/
You can also vote for support for it to be added to other Microsoft tools here:
https://visualstudio.uservoice.com/forums/121579-visual-studio-ide/suggestions/17608120-properly-support-native-thread-naming-via-the-sett

Dont have wpa installed handy so cant answer your query but thanks for
the question it never occurred to me that this could be used native code too
could come in handy
#include <windows.h>
#include <stdio.h>
const DWORD MS_VC_EXCEPTION=0x406D1388;
//EmptyBlock,Constant in__except() and lpparam not used in ThreadProc
#pragma warning( disable : 6312 6322 4100 )
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO {
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
DWORD WINAPI ThreadProc( LPVOID lpParam ) {
int ch = 0; while(ch != 'y') { ch = getchar(); } return 0;}
void SetThreadName( DWORD dwThreadID, char* threadName) {
THREADNAME_INFO info; info.dwType = 0x1000; info.szName = threadName;
info.dwThreadID = dwThreadID; info.dwFlags = 0;
__try {
RaiseException( MS_VC_EXCEPTION, 0,
sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except( EXCEPTION_CONTINUE_EXECUTION) { }
}
void main (void) {
HANDLE hThread = NULL;
printf("\n\n\n=======Creating Thread And Naming It================\n\n\n");
if (( hThread = CreateThread(NULL,NULL,ThreadProc,NULL,NULL,NULL)) != NULL) {
SetThreadName(GetCurrentThreadId(), "\n\nMy New Shiny Thread\n\n");
WaitForSingleObject(hThread,INFINITE);
printf("Named Thread Terminated Main is terminating\n");
CloseHandle(hThread);
}
}
compiled linked and windbagged vcpp event seems to handle this exception in windbg
wonder what MAGIC Dword dbce handles
dir /b
compile.bat
threadname.cpp
type compile.bat
#call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
cl /Zi /nologo /W4 /analyze *.cpp /link /RELEASE
compile.bat
Setting environment for using Microsoft Visual Studio 2010 x86 tools.
threadname.cpp
dir /b *.exe
threadname.exe
cdb -c "sxe -c \"~*;gc;\" vcpp;g;q" threadname.exe
0:000> cdb: Reading initial command 'sxe -c "~*;gc;" vcpp;g;q'
=================Creating Thread And Naming It===================
(f84.db4): Visual C++ exception - code 406d1388 (first chance)
. 0 Id: f84.db4 Suspend: 1 Teb: 7ffdf000 Unfrozen "
My New Shiny Thread
"
Start: threadname!mainCRTStartup (00401642)
Priority: 0 Priority class: 32 Affinity: 1
y
Named Thread Terminated Main is terminating
quit:

Related

Weird case of AccessViolation while using overlapped IO in Windows

I've been experimenting with Overlapped IO feature of Win32 API, namely ReadFileEx and WriteFileEx functions.
Here is a simplest example:
#include <iostream>
#include <string>
#include <Windows.h>
const DWORD blockSize = 512;
char buffer[blockSize];
bool done = false;
OVERLAPPED overlapped;
void Completion(DWORD error, DWORD read, LPOVERLAPPED overlapped) {
}
int _tmain(int argc, _TCHAR* argv[])
{
std::wstring fileName;
std::wcout << "Enter file name: ";
std::getline(std::wcin, fileName);
HANDLE file = CreateFile(
fileName.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (file == INVALID_HANDLE_VALUE) {
std::wcout << "Error while opening file: " << GetLastError() << std::endl;
std::cin.get();
return -1;
}
overlapped.Offset = overlapped.OffsetHigh = 0;
ReadFileEx(file, buffer, blockSize, &overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) &Completion);
while (!done)
SleepEx(1000, TRUE);
return 0;
}
As you can see, I'm starting overlapped reading with ReadFileEx and waiting for it to finish using SleepEx. Although Completion has empty body and the program should hang forever after reading first block, it does something completely different. In fact, it raises AccessViolation with code 0xC0000005 on the first call to SleepEx. This happens on Windows machines with Win 7 and Win Vista I've tried, including fresh 64 bit virtual machine with Windows 7. But, curiously, it does not fail on one Windows 8.1 machine and runs just as expected. This was compiled with Visual Studio 2010, but I don't think it matters.
I can not understand what have I done wrong, so if anyone knows the answer, please help me.
The callback must be of the following form, as stated clearly in the documentation:
VOID CALLBACK FileIOCompletionRoutine(
_In_    DWORD        dwErrorCode,
_In_    DWORD        dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped
);
Your function has the wrong calling convention. Your cast does not change that. It is simply a way for you to stop the compiler rejecting your ill-formed program. Don't lie to the compiler. Correct the function declaration by adding the CALLBACK calling convention.

Assembly program runs and immediately crashes without printing the Hello World message

Ok so basically I was just writing a C program to build my object files and then create executeables from them by using nasm and ld respectively
The program I wrote makes the correct calls to nasm and ld but I either compile fine with -f win32/win64 ( I'm on a 64 bit windows 7 machine ) or fail with the other options which is fine though... right? If the program compiles and creates the exe it runs and immediately crashes without printing the Hello World message. I'd Really like to jump into assembly. Some Help ?
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ah,00
int 16h
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!', 0xa ;our dear string
len equ $ - msg ;length of our dear string
I also happen to have a kali system ; I don't suppose I could compile for both operating systems without using Wine?
So my C program is working nicely! I can't find any examples of code to assemble though. Well I can... but it all fails. Does anyone have a link?
#include <stdio.h>
#include <stdlib.h>
#include <CustomHeader_Small.h>
void Assemble(void);
void PrintMenu(void);
void LoadOptions(void);
void SaveOptions(void);
char TempBuff[255];
char Format[30];
void SaveOptions(void)
{
FILE *Source = fopen("Settings.ini","w");
if(Source)
{
printf("%s","Enter A Format Type ->");
scanf("%s",Format); //Save Format
fprintf(Source,"Format:%s",Format);
fclose(Source);
puts("Settings Updated!");
LoadOptions();
}
return;
}
void LoadOptions(void)
{
FILE *Source = fopen("Settings.ini","r");
if(Source)
{
char ch;
int i;
char Line[50];
fscanf(Source,"%s",Line);
CCopy(Line,CPos(Line,":",0)+1,CLen(Line),Format,0,1);
free(Line);
}
else
{
Source = fopen("Settings.ini","w");
fprintf(Source,"%s","Format:Win32");
fclose(Source);
}
PrintMenu();
LoadOptions();
return;
}
void PrintMenu(void)
{
printf("%s","Menu:\n________\n1.) [C]reate A New Project.\n2.) [O]pen A Project.\n3.) [A]ssemble A Project.\n4.) [E]dit Settings\n");
printf("%s","5.) [Q]uit\n");
return;
}
void Assemble(void)
{
char *File=malloc(256);
printf("Note : Compiling In %s Mode\n",Format);
printf("%s","Enter A Project Name -> ");
scanf("%s",File);
char *Command;
int ch;
while((ch=getchar())!='S')
{
Command=malloc(1024);
strcpy(Command,"H:\\Users\\Grim\\AppData\\Local\\nasm\\nasm.exe -f ");
strcat(Command,Format);
strcat(Command," ");
strcat(Command,File);
strcat(Command,"\\");
strcat(Command,File);
strcat(Command,".asm ");
strcat(Command,"-o ");
strcat(Command,File);
strcat(Command,"\\");
strcat(Command,File);//This Creates The Object File Using Nasm ( Not Just Yet But Were Well On Our Way!
strcat(Command,".o");
system(Command); //Calls Nasm.
free(Command);
Command=malloc(1024);
strcpy(Command,"H:\\MinGW\\bin\\ld.exe ");
strcat(Command,File);
strcat(Command,"\\");
strcat(Command,File);
strcat(Command,".o ");
strcat(Command,"-o ");
strcat(Command,File);//This Creates The Executable File Using Nasm ( Not Just Yet But Were Well On Our Way!
strcat(Command,"\\");
strcat(Command,File);
strcat(Command,".exe");
system(Command); //Calls Nasm.
free(Command);
puts("Press Enter To Compile Again But Enter An [S] Followed By Enter To [S]top.");
}
free(File);
puts("NasmWrapper Assembly Done!");
printf("%s","\n\n\n");
PrintMenu();
return;
}
int main()
{
LoadOptions();
char ch;
while((ch = getchar())!='Q')
{
if(ch=='A') Assemble();
if(ch=='E') SaveOptions();
}
return 0;
}
Also any comments on the C program would be nice :D Thanks for explaining how to use the [Code] thing.
Your assembly program, apart from that odd int 16h* is specifically for Linux (32-bit Linux, to be more precise). int 0x80 is the way you invoke one of the Linux kernel system calls.
Windows doesn't do it this way. Instead you call the Windows API or the C standard library.
This OS-specific variation is one of the reasons it is good to use a higher level language rather than assembly.
If you want to play with assembly, my recommendation would be to decide on which OS you want to start with, and use that exclusively to begin with. Find some tutorials (there are lots for Linux and Windows) and get started. Once you have got it working for one OS, try it for another.
* int 16h calls the BIOS from DOS. This won't work in Linux.

Best way to have crash dumps generated when processes crash?

In Windows environments (XP and Win 7):
What is the best way to automatically have a crash dump generated when processes crash on the system?
Can an installer (MSI) package do this?
One of the best way to have an automatic dump for any/specific process on Windows is to configure a set of entries in the registry. I tried the below on Windows 7 64 bit.
Open notepad.exe, paste the below entry and save it as "EnableDump.reg". You can give any name you wish.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps]
"DumpFolder"=hex(2):44,00,3a,00,5c,00,64,00,75,00,6d,00,70,00,00,00
"DumpCount"=dword:00000010
"DumpType"=dword:00000002
"CustomDumpFlags"=dword:00000000
Double click the "EnableDump.reg" and select 'Yes'. I have given the dump folder as 'd:\dump'. You can change it to whatever folder you wish.
Try to execute a crashing application, Windows will display the error dialog. Choose 'Close the Program' option. After that you will see the dump in the configured folder. The name of the dump file will be .exe..dmp.
For more details, you can refer the below link.
http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx
Below explanation is based on another answer, but the logic is mine (without attribution need, as said on my profile);
Having your own dump generation framework which automatically creates a process dump when any Unhandled exception is encountered, would avoid clients having to install WinDbg.
At the application start up use SetUnhandledExceptionFilter(...) Win32 API to register a callback (i.e. application level exception-handler).
Now the registered callback function is called whenever there is any exception which is not handled. You may then create the process dump using MiniDumpWriteDump(...) API from DbgHelp.dll.
C++ Sample (unicode-enabled)
header-file
#ifndef CRASH_REPORTER_H
#define CRASH_REPORTER_H
//Exclude rarely used content from the Windows headers.
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
#else
# include <windows.h>
#endif
#include <tchar.h>
#include <DbgHelp.h>
class CrashReporter {
public:
inline CrashReporter() { Register(); }
inline ~CrashReporter() { Unregister(); }
inline static void Register() {
if(m_lastExceptionFilter != NULL) {
fprintf(stdout, "CrashReporter: is already registered\n");
fflush(stdout);
}
SetErrorMode(SEM_FAILCRITICALERRORS);
//ensures UnHandledExceptionFilter is called before App dies.
m_lastExceptionFilter = SetUnhandledExceptionFilter(UnHandledExceptionFilter);
}
inline static void Unregister() {
SetUnhandledExceptionFilter(m_lastExceptionFilter);
}
private:
static LPTOP_LEVEL_EXCEPTION_FILTER m_lastExceptionFilter;
static LONG WINAPI UnHandledExceptionFilter(_EXCEPTION_POINTERS *);
};
#endif // CRASH_REPORTER_H
source-file
#include "crash-report.h"
#include <stdio.h>
LPTOP_LEVEL_EXCEPTION_FILTER CrashReporter::m_lastExceptionFilter = NULL;
typedef BOOL (WINAPI *MiniDumpWriteDumpFunc)(HANDLE hProcess, DWORD ProcessId
, HANDLE hFile
, MINIDUMP_TYPE DumpType
, const MINIDUMP_EXCEPTION_INFORMATION *ExceptionInfo
, const MINIDUMP_USER_STREAM_INFORMATION *UserStreamInfo
, const MINIDUMP_CALLBACK_INFORMATION *Callback
);
LONG WINAPI CrashReporter::UnHandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtr)
{
//we load DbgHelp.dll dynamically, to support Windows 2000
HMODULE hModule = ::LoadLibraryA("DbgHelp.dll");
if (hModule) {
MiniDumpWriteDumpFunc dumpFunc = reinterpret_cast<MiniDumpWriteDumpFunc>(
::GetProcAddress(hModule, "MiniDumpWriteDump")
);
if (dumpFunc) {
//fetch system time for dump-file name
SYSTEMTIME SystemTime;
::GetLocalTime(&SystemTime);
//choose proper path for dump-file
wchar_t dumpFilePath[MAX_PATH] = {0};
_snwprintf_s(dumpFilePath, MAX_PATH, L"crash_%04d-%d-%02d_%d-%02d-%02d.dmp"
, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay
, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond
);
//create and open the dump-file
HANDLE hFile = ::CreateFileW( dumpFilePath, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN
, NULL
);
if (hFile != INVALID_HANDLE_VALUE) {
_MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
exceptionInfo.ThreadId = GetCurrentThreadId();
exceptionInfo.ExceptionPointers = exceptionPtr;
exceptionInfo.ClientPointers = NULL;
//at last write crash-dump to file
bool ok = dumpFunc(::GetCurrentProcess(), ::GetCurrentProcessId()
, hFile, MiniDumpNormal
, &exceptionInfo, NULL, NULL
);
//dump-data is written, and we can close the file
CloseHandle(hFile);
if (ok) {
//Return from UnhandledExceptionFilter and execute the associated exception handler.
// This usually results in process termination.
return EXCEPTION_EXECUTE_HANDLER;
}
}
}
}
//Proceed with normal execution of UnhandledExceptionFilter.
// That means obeying the SetErrorMode flags,
// or invoking the Application Error pop-up message box.
return EXCEPTION_CONTINUE_SEARCH;
}
usage
#include "3rdParty/crash-report.h"
int main(int argc, char *argv[])
{
CrashReporter crashReporter;
(void)crashReporter; //prevents unused warnings
// [application main loop should be here]
return 0;
}
Windows XP:
The following steps enable automatic crash dumps:
1) Open a command prompt, running as administrator
2) Run drwtsn32 -i. This will install Doctor Watson as the default debugger when something crashes
3) Click Ok
4) From the command prompt, run drwtsn32
5) Set the Crash Dump path to your favorite directory, or leave the default.
6) Set the Crash Dump Type to mini. Note that under some circumstances, we may ask you for a full crash dump.
7) Make sure the Dump All Thread Contexts and Create Crash Dump File options are selected.
8) Click Ok
9) If a user.dmp file already exists in the Crash Dump path, delete it.
Windows 7: Location is:
C:\Users[Current User when app crashed]\AppData\Local\Microsoft\Windows\WER\ReportArchive

SysInternal's WinObj device listing mechanism

SysInternals's WinObj can list all device objects.
I wonder how it can list the devices.
Is there any open source we can read?(or a code snippet)
What is the most significant function I should know?
WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.
You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.
According to SysInternals' web page:
The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.
I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(
As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.
Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.
But here's a simple C++ code example catering just your use case:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.
The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).
Disclosure: I am the author of ntobjx.
You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.
To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.
"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."
You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

SUA + Visual Studio + pthreads

I cannot compile this code under SUA:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void * thread_function(void *arg) {
printf("thread_function started. Arg was %s\n", (char *)arg);
// pause for 3 seconds
sleep(3);
// exit and return a message to another thread
// that may be waiting for us to finish
pthread_exit ("thread one all done");
}
int main() {
int res;
pthread_t a_thread;
void *thread_result;
// create a thread that starts to run ‘thread_function’
pthread_create (&a_thread, NULL,
thread_function, (void*)"thread one");
printf("Waiting for thread to finish...\n");
// now wait for new thread to finish
// and get any returned message in ‘thread_result’
pthread_join(a_thread, &thread_result);
printf("Thread joined, it returned %s\n", (char *)thread_result);
exit(0);
}
I'm running on Windows 7 Ultimate x64 with Visual Studio 2008 and 2010 and I have installed:
Windows Subsystem for UNIX
Utilities and SDK for Subsystem for UNIX-based Applications in Microsoft Windows 7 and Windows Server 2008 R2
Include directories property of Visual Studio project is set to "C:\Windows\SUA\usr\include"
What I have to configure in order to compile and run (and possibly debug) pthreads programs in Visual Studio 2010 (or 2008)?

Resources