1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <Windows.h>
// ============================================================
// Child Process (Consumer)
// ============================================================
#define BUFFSIZE 1024U
static int child_process(void)
{
puts("Hello from the \"child\" process!\n");
char buffer[BUFFSIZE];
for (;;) {
if (fgets(buffer, BUFFSIZE, stdin) != NULL) {
printf("> %s", buffer);
}
else {
return EXIT_SUCCESS;
}
}
}
// ============================================================
// Main Process (Producer)
// ============================================================
#define THREAD_COUNT 5U
static unsigned _stdcall thread_function(void *data)
{
FILE *const output = (FILE*)data;
const DWORD id = GetCurrentThreadId();
Sleep(3000U);
DWORD counter = 0U;
for (size_t i = 0U; i < 32U; ++i) {
if (i > 0U) {
Sleep(1000U);
}
fprintf(output, "Message #%u from worker thread 0x%X is here!\n", counter++, id);
fflush(output);
}
return 0U;
}
static FILE *wrap_handle(const HANDLE handle, const BOOL write)
{
const int fdesc = _open_osfhandle((intptr_t)handle, write ? _O_WRONLY : _O_RDONLY);
if (fdesc >= 0) {
FILE *const stream = _fdopen(fdesc, write ? "w" : "r");
if (!stream) {
_close(fdesc);
}
return stream;
}
return NULL;
}
// ---------------------------------------------------
// Main function
// ---------------------------------------------------
static int main_process(void)
{
puts("Hello from the \"main\" process!\n");
// ---------------------------------------------------
// Build the command-line
// ---------------------------------------------------
wchar_t filename[BUFFSIZE];
DWORD result = GetModuleFileNameW(NULL, filename, BUFFSIZE);
if (!((result > 0U) && (result < BUFFSIZE))) {
fputs("Failed to get executable file path!\n", stderr);
return EXIT_FAILURE;
}
wchar_t commandline[BUFFSIZE];
if (_snwprintf_s(commandline, BUFFSIZE, _TRUNCATE, L"\"%s\" --child", filename) < 0) {
fputs("Failed to build the command-line!\n", stderr);
return EXIT_FAILURE;
}
// ---------------------------------------------------
// Create child processes
// ---------------------------------------------------
HANDLE child_process[THREAD_COUNT];
FILE *console[THREAD_COUNT]; /* the "write" handles of the pipe(s), already wrapped as FILE stream(s) */
SecureZeroMemory(child_process, sizeof(child_process));
SecureZeroMemory(console, sizeof(console));
puts("Creating child processes, please wait...");
for (size_t i = 0U; i < THREAD_COUNT; ++i) {
HANDLE hPipeRead = INVALID_HANDLE_VALUE, hPipeWrite = INVALID_HANDLE_VALUE;
if (!CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0U)) {
fputs("Failed to create new pipe for child-process!\n", stderr);
return EXIT_FAILURE;
}
if (!SetHandleInformation(hPipeRead, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
fputs("Failed to update handle information!\n", stderr);
return EXIT_FAILURE;
}
if (!(console[i] = wrap_handle(hPipeWrite, TRUE))) {
fputs("Failed to wrap the console \"write\" handle!!\n", stderr);
}
STARTUPINFOW startup;
SecureZeroMemory(&startup, sizeof(STARTUPINFOW));
startup.cb = sizeof(STARTUPINFOW);
startup.dwFlags = STARTF_USESTDHANDLES;
startup.hStdInput = hPipeRead;
PROCESS_INFORMATION info;
SecureZeroMemory(&info, sizeof(PROCESS_INFORMATION));
if (!CreateProcessW(NULL, commandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &info)) {
fputs("Failed to create child process!\n", stderr);
return EXIT_FAILURE;
}
child_process[i] = info.hProcess;
CloseHandle(hPipeRead);
CloseHandle(info.hThread);
}
// ---------------------------------------------------
// Create worker threads
// ---------------------------------------------------
puts("Done.\n\nCreating worker threads, please wait...");
HANDLE threads[THREAD_COUNT];
for (size_t i = 0U; i < THREAD_COUNT; ++i) {
if (!(threads[i] = (HANDLE)_beginthreadex(NULL, 0U, thread_function, console[i], 0U, NULL))) {
fputs("Failed to create child process!\n", stderr);
return EXIT_FAILURE;
}
}
// ---------------------------------------------------
// Wait for completion
// ---------------------------------------------------
puts("Done.\n\nWaiting for worker threads to finish, please wait...");
WaitForMultipleObjects(THREAD_COUNT, threads, TRUE, INFINITE);
for (size_t i = 0U; i < THREAD_COUNT; ++i) {
CloseHandle(threads[i]);
}
// ---------------------------------------------------
// Final clean-up
// ---------------------------------------------------
puts("Done.\n\nPress any key...");
getchar();
for (size_t i = 0U; i < THREAD_COUNT; ++i) {
fclose(console[i]);
}
puts("\nWaiting for child processes to exit, please wait...");
WaitForMultipleObjects(THREAD_COUNT, child_process, TRUE, INFINITE);
for (size_t i = 0U; i < THREAD_COUNT; ++i) {
CloseHandle(child_process);
}
puts("Done.\n");
return EXIT_SUCCESS;
}
// ============================================================
// Entry point
// ============================================================
int wmain(int argc, wchar_t *argv[])
{
if (argc > 1) {
if (_wcsicmp(argv[1], L"--child") == 0) {
return child_process();
}
else {
fputs("Error: Bad arguments detected !!!", stderr);
return EXIT_FAILURE;
}
}
return main_process();
}
|