/* ================================================ mingw64でfork(),waitpid(), kill()を何とかしたい ================================================ ●参照させて頂いたページ https://gist.github.com/Cr4sh/126d844c28a7fbfd25c6 http://7shi.hateblo.jp/entry/2012/06/19/213405 http://www.fireproject.jp/feature/c-language/process/fork-wait.html ●コンパイル: gcc -c fork.cpp ●その他 「mingw64でfork()を何とかしたい」の後に読むと分かりやすいかも ちなみにWindowsのコマンドプロンプトではprintf()の表示がされない(理由不明)ので > fork2 > dummy.txt などとして確認すること。 */ /* * fork.c * Experimental fork() on Windows. Requires NT 6 subsystem or * newer. * * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _WIN32_WINNT 0x0600 #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winnt.h> #include <ntdef.h> #include <stdio.h> #include <errno.h> #include <process.h> #ifdef __MINGW32__ typedef struct _CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _SECTION_IMAGE_INFORMATION { PVOID EntryPoint; ULONG StackZeroBits; ULONG StackReserved; ULONG StackCommit; ULONG ImageSubsystem; WORD SubSystemVersionLow; WORD SubSystemVersionHigh; ULONG Unknown1; ULONG ImageCharacteristics; ULONG ImageMachineType; ULONG Unknown2[3]; } SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; typedef struct _RTL_USER_PROCESS_INFORMATION { ULONG Size; HANDLE Process; HANDLE Thread; CLIENT_ID ClientId; SECTION_IMAGE_INFORMATION ImageInformation; } RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; #define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 #define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 #define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 #define RTL_CLONE_PARENT 0 #define RTL_CLONE_CHILD 297 #endif typedef NTSTATUS (*RtlCloneUserProcess_f) (ULONG ProcessFlags, PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, HANDLE DebugPort /* optional */, PRTL_USER_PROCESS_INFORMATION ProcessInformation); pid_t fork(void) { HMODULE mod; RtlCloneUserProcess_f clone_p; RTL_USER_PROCESS_INFORMATION process_info; NTSTATUS result; mod = GetModuleHandle("ntdll.dll"); if (!mod) return -ENOSYS; //clone_p = GetProcAddress(mod, "RtlCloneUserProcess"); // Ebata clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, "RtlCloneUserProcess"); if (clone_p == NULL) return -ENOSYS; /* lets do this */ result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); if (result == RTL_CLONE_PARENT) { HANDLE me = GetCurrentProcess(); pid_t child_pid; child_pid = GetProcessId(process_info.Process); ResumeThread(process_info.Thread); CloseHandle(process_info.Process); CloseHandle(process_info.Thread); return child_pid; } else if (result == RTL_CLONE_CHILD) { /* fix stdio */ AllocConsole(); return 0; } else return -1; /* NOTREACHED */ return -1; } int kill(pid_t pid, int sig) { int ret; HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); ret = TerminateProcess(h, 0) ? 0 : -1; CloseHandle(h); return ret; } #if 0 int waitpid(pid_t pid, int *stat_loc, int options) { int i = 1; return _cwait(stat_loc, pid, WAIT_CHILD); } #endif int waitpid(pid_t pid, DWORD dwMilliseconds) // Ebata's original waitpid() { HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); // WaitForSingleObject(h, INFINITE); int ret = WaitForSingleObject(h, dwMilliseconds); CloseHandle(h); return ret; } #if 0 // サンプルプログラム int main(void){ pid_t result_pid = fork(); if (result_pid == 0){ // 子プロセス printf("Child process started.\n"); printf("Wait 10 seconds.\n"); printf("result_pid = %d child process.\tpid = %d\n",result_pid,getpid()); fflush(stdout); Sleep(10000); // 10秒くらいの生存期間 fprintf(stdout,"Child process ended.\n"); fflush(stdout); } else{ // 親プロセス printf("Parents process started.\n"); fflush(stdout); // 親プロセスの方には、子プロセスのIDが入るので、それを監視する waitpid(result_pid, INFINITE); // 子プロセス(1つのみ)が終了するまで止まる //waitpid(result_pid, 100); // 100msのみ停止 fprintf(stdout,"Parent process ended.\n"); fflush(stdout); } return 0; } #endif // サンプルプログラム ========================================================== /* シュタインズゲートの「タイムリープ」をコーディングするとこんな感じ gcc -c fork_test.cpp gcc -g fork.cpp fork_test.cpp -o fork_test */ #include <windows.h> #include <stdio.h> #include <process.h> extern pid_t fork(void); extern int waitpid(pid_t pid, DWORD dwMilliseconds); // Ebata's original waitpid() extern int kill(pid_t pid, int sig); int main(void){ pid_t result_pid = -1; // fork()が吐き出さない値をダミーに入れておく int init_i = -1; for (int i = 0; i < 100; i++){ if (i == 17){ // iが17になった時に、子プロセスを起動 result_pid = fork(); init_i = i ; } if (result_pid == 0){ // 子プロセス printf("c:\t%d\n", i); fflush(stdout); if (i > init_i + 50){ // 「岡部、50回先の未来に行く」 exit(0); // 子プロセスの強制終了 } } else { waitpid(result_pid, INFINITE); // 子プロセス(1つのみ)が終了するまで止まる printf("p:%d\n", i);// 「岡部、リーディングシュタイナー発動(記憶を維持したまま、50回前の過去にタイムリープ」 fflush(stdout); } } }