I am learning OS development with C/C++ and i am using fork() method to experiment with process. I have the following code like this:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
fork(); //create a child process, currently total is 1 parent, 1 child
fork(); //create a child process,currently total is 2 parents, 2 child
pid_t pid;
if((pid=fork()) == 0) { //fork() and assign to pid, now has 4 parents, 4 childs
printf("I am the child: %u\n", getpid());
else {
printf("I am the parent: %u and my child is: %u\n", getpid(), pid);
}
}
When i compile it, and run it, it shows 4 parents and 4 children as i expected, however the output looks strange to me (notice the bolded line below where i get the output after user#slacker:~$).
user#slacker:~$ gcc forktest.c -o forktest
user#slacker:~$ ./forktest
I am the parent: 1183 and my child is: 1186
user#slacker:~$ I am the parent: 1184 and my child is: 1188
I am the parent: 1185 and my child is: 1189
I am the parent: 1187 and my child is: 1190
I am the child: 1186
I am the child: 1189
I am the child: 1190
I am the child: 1191
When i tried with 3 fork(), the output is even stranger. Can someone explain to me please?
fork fork fork
1183----+---------------+----------------+-------------------->
| | |
| | 1186 +-------------------->
| |
| 1185 +----------------+-------------------->
| |
| 1189 +-------------------->
|
1184 +---------------+----------------+-------------------->
| |
| 1188 +-------------------->
|
1187 +----------------+-------------------->
|
1190 +-------------------->
created with http://www.asciiflow.com/#Draw
Related
So I am trying to run 3 commands in a sequential way.
ls -l / | grep a | sort -r
However, my code seems to hang the process. I know that this usually indicated an unhandled pipe. but I can't seem to find the problem, I have closed all possible file descriptors that I could find.
Code may have some meaningless lines like closing the same FD twice, which I added while trying to fix it
#include <iostream>
#include<unistd.h>
#include <sys/wait.h>
using namespace std;
#define pipeWrite 1
#define pipeRead 0
// Main Function
int main() {
//Command to run: ls -l / | grep a | sort -r | wc > count.txt
// Total 4 commands to run, so 4 child processes.
pid_t c1,c2,c3,c4;
// File Descriptors
int pipeFD_1[2];
int pipeFD_2[2];
pipe(pipeFD_1);
// To execute ls -l
c1 = fork();
// Child
if (c1 == 0) {
// Closing input end
close(1);
dup(pipeFD_1[1]);
close(pipeFD_1[0]);
close(pipeFD_1[1]);
// Running command
execl("/bin/ls", "ls", "-l", "/",NULL);
}
pipe(pipeFD_2);
c2 = fork();
if (c2 == 0) {
// Closing output end
close(0);
dup(pipeFD_1[0]);
close(1);
dup(pipeFD_2[1]);
close(pipeFD_1[0]);
close(pipeFD_1[1]);
close(pipeFD_2[0]);
close(pipeFD_2[1]);
// Running command
execl("/bin/grep", "grep", "a", NULL);
}
//Closing pipe 1.
close(pipeFD_1[0]);
close(pipeFD_1[1]);
c3 = fork();
if (c3 == 0) {
// Closing out end
close(0);
dup(pipeFD_2[0]);
close(pipeFD_2[0]);
close(pipeFD_2[1]);
// Running command
execl("/bin/sort", "sort", "-r", NULL);
}
// Since exec auto exits the child process. No need to put else.
// Closing output end
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
exit(0);
}
EDIT: Fixed by adding 2 more lines after the third fork, closing FDs for pipe2 (for parent).
Thank you Barmar and ItsHoney for your valuable discussions. Posting them as answer to help other community members.
Fixed by adding 2 more lines after the third fork, closing FDs for pipe2 (for parent).
#include <iostream>
#include<unistd.h>
#include <sys/wait.h>
using namespace std;
#define pipeWrite 1
#define pipeRead 0
// Main Function
int main() {
//Command to run: ls -l / | grep a | sort -r | wc > count.txt
// Total 4 commands to run, so 4 child processes.
pid_t c1,c2,c3,c4;
// File Descriptors
int pipeFD_1[2];
int pipeFD_2[2];
pipe(pipeFD_1);
// To execute ls -l
c1 = fork();
// Child
if (c1 == 0) {
// Closing input end
close(1);
dup(pipeFD_1[1]);
close(pipeFD_1[0]);
close(pipeFD_1[1]);
// Running command
execl("/bin/ls", "ls", "-l", "/",NULL);
}
pipe(pipeFD_2);
c2 = fork();
if (c2 == 0) {
// Closing output end
close(0);
dup(pipeFD_1[0]);
close(1);
dup(pipeFD_2[1]);
close(pipeFD_1[0]);
close(pipeFD_1[1]);
close(pipeFD_2[0]);
close(pipeFD_2[1]);
// Running command
execl("/bin/grep", "grep", "a", NULL);
}
//Closing pipe 1.
close(pipeFD_1[0]);
close(pipeFD_1[1]);
c3 = fork();
if (c3 == 0) {
// Closing out end
close(0);
dup(pipeFD_2[0]);
close(pipeFD_2[0]);
close(pipeFD_2[1]);
// Running command
execl("/bin/sort", "sort", "-r", NULL);
}
// Since exec auto exits the child process. No need to put else.
// Closing output end
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
exit(0);
}
This question already has answers here:
Why getppid() from the child return 1
(2 answers)
Closed 6 years ago.
In order to explain the question I'm asking let's consider this code,
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
pid_t child, parent;
parent = getpid();
printf("Main parent pid: %d\n",parent );
if((child = fork()) < 0) {
printf("Error\n");
} else if(child == 0 ) {
printf("A Child process is created, pid: %d, ppid: %d \n",
getpid(), getppid());
} else if(child > 0) {
printf("Parent says: Child pid: %d, getpid: %d, getppid: %d\n",
child, getpid(), getppid());
}
return 0;
}
When I execute this code on terminal I get such an output
Main pid: 711
Parent says: Child pid: 712, getpid: 711, getppid: 598
A Child process is created, pid: 712, ppid: 1
As far as I understand, when I'm creating a new process by forking from a already created process, the parent of this new process must the process that I have forked.Hovewer, as you can see from the output, the parent process ID of the child is 1, i.e the init process, so why is that so ? Is my understand wrong, or there is some other things that I'm not seeing ?
Note: I'm working on Mac OSX.
The problem is that the parent process (711) has died and the child process inherited by the init process (1) before it gets to report. If you have the parent wait for the child to die before exiting itself, you'll see the result you expect.
To demonstrate:
#include <sys/wait.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
pid_t child, parent;
parent = getpid();
printf("Main parent pid: %d\n", (int)parent);
if ((child = fork()) < 0)
{
printf("Error\n");
}
else if (child == 0)
{
printf("A Child process is created, pid: %d, ppid: %d\n",
(int)getpid(), (int)getppid());
}
else if (child > 0)
{
printf("Parent says: Child pid: %d, getpid: %d, getppid: %d\n",
(int)child, (int)getpid(), (int)getppid());
#ifndef DO_NOT_WAIT_FOR_CHILD
int status;
int corpse = wait(&status);
printf("Child %d exited with status 0x%.4X\n", corpse, status);
#endif
}
return 0;
}
When compiled without -DDO_NOT_WAIT_FOR_CHILD, I got the sample output:
Main parent pid: 77646
Parent says: Child pid: 77647, getpid: 77646, getppid: 46383
A Child process is created, pid: 77647, ppid: 77646
Child 77647 exited with status 0x0000
When compiled with -DDO_NOT_WAIT_FOR_CHILD, I got the sample output:
Main parent pid: 77662
Parent says: Child pid: 77663, getpid: 77662, getppid: 46383
A Child process is created, pid: 77663, ppid: 1
I am using two forks in my code:
int main()
{
cout<<"Main Process ID is: "<<getpid()<<endl;
int processID;
processID = fork();
cout<<"Part 1"<<endl;
cout<<"PID is: "<<getpid()<<" Child PID: "<<processID<<" Parent PID: "<<getppid()<<endl;
processID = fork();
cout<<"Part 2"<<endl;
cout<<"PID is: "<<getpid()<<" Child PID: "<<processID<<" Parent PID: "<<getppid()<<endl;
return 0;
}
But there are some strange "Parent ID" for "children". Why? (Please refer to screenshot below)
Thanks a lot in advance.
In your case the parent executed first, hence got eventually terminated. In this case child become orphan and hence it's parent id got replaced with the id of other process in same group or the child got re-parented.Hence, the parent id is different(strange).
i have searched on so many websites after "how i get the conhost process", and nothing is really what i'm looking for.
i have searched on.
superuser/stackoverflow when-is-conhost-exe-actually-necessary
stackoverflow how-can-a-win32-process-get-the-pid-of-its-parent
stackoverflow c-how-to-fetch-parent-process-id
stackoverflow c-how-to-determine-if-a-windows-process-is-running
stackoverflow get-full-running-process-list-visual-c
stackoverflow ms-c-get-pid-of-current-process
stackoverflow get-list-of-dlls-loaded-in-current-process-with-their-reference-counts
codeproject Get-Parent-Process-PID
cplusplus Getting list of running processes
msdn.microsoft GetModuleFileNameEx
msdn.microsoft GetModuleFileName
msdn.microsoft GetCurrentProcessId
msdn.microsoft GetProcessId
msdn.microsoft GetModuleHandle
msdn.microsoft GetConsoleWindow
msdn.microsoft Tool Help
msdn.microsoft CreateToolhelp32Snapshot
msdn.microsoft NextModule32
msdn.microsoft DebugActiveProcess
msdn.microsoft Enumerating All Modules For a Process
and i can't find anything about "how to get the conhost process".
i have some code that works for the current "cmd.exe / program.exe" and that gives me the "PID, NAME, PATH, READ/WRITE ADDRESS".
i can get the parent process but that is not conhost.exe.
code "need to link library 'psapi' first":
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
#include <iostream>
#include <tlhelp32.h>
int PrintModules(DWORD processID) {
HMODULE hMods[1024];
HANDLE hProcess;
DWORD cbNeeded;
unsigned int i;
printf( "\nProcess ID: %u\n", processID);
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if(NULL == hProcess) return 1;
if(EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
for(i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
TCHAR szModName[MAX_PATH];
if(GetModuleFileNameEx(hProcess, hMods[i], szModName,sizeof(szModName) / sizeof(TCHAR))) {
_tprintf( TEXT(" %s (0x%08X)\n"), szModName, hMods[i]);
}
}
}
CloseHandle(hProcess);
return 0;
}
int main(void) {
DWORD cpid = GetCurrentProcessId();
PrintModules(cpid);
int ppid = -1;
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
if(Process32First(h, &pe)) {
do {
if(pe.th32ProcessID == cpid) {
printf("PID: %i; PPID: %i\n", cpid, pe.th32ParentProcessID);
ppid = pe.th32ParentProcessID;
}
} while(Process32Next(h, &pe));
}
PrintModules(ppid);
CloseHandle(h);
std::cin.get();
return 0;
}
and i can't figure out a way to get the current conhost process.
when you open a program that uses the console, a conhost.exe process is created.
and my question is how do i get that conhost.exe process...
Thanks! :)
In case you still need it (after reading the comments), here's a piece of code that gets the conhost.exe processes. Please note that I only wrote it for demonstrative purposes (to check whether [MSDN]: Tool Help Functions can be used for this scenario), so don't mind its structure or other coding NO-NOs.
code.c:
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
int main(int argc, char **argv) {
DWORD pid = 0, i = 0, cPid = 0;
PROCESSENTRY32 pe32;
BOOL res = FALSE;
HANDLE snap = INVALID_HANDLE_VALUE, proc = INVALID_HANDLE_VALUE;
char c = 0;
if (argc > 1) {
pid = atoi(argv[1]);
} else {
pid = GetCurrentProcessId();
}
printf("PID: %d\n", pid);
snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid);
if (snap == INVALID_HANDLE_VALUE) {
printf("CreateToolhelp32Snapshot failed: %d\n", GetLastError());
return -1;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
res = Process32First(snap, &pe32);
if (res == FALSE) {
printf("Process32First failed: %d\n", GetLastError());
CloseHandle(snap);
return -2;
}
do {
if (_tcscmp(pe32.szExeFile, TEXT("conhost.exe")) == 0) {
_tprintf(TEXT(" Idx: %02d PID: %5d PPID: %5d Name: %s\n"), i++, pe32.th32ProcessID, pe32.th32ParentProcessID, pe32.szExeFile);
if (pe32.th32ParentProcessID == pid) {
cPid = pe32.th32ProcessID;
}
}
} while ((res = Process32Next(snap, &pe32)));
CloseHandle(snap);
if ((proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, cPid)) == INVALID_HANDLE_VALUE) {
printf("OpenProcess failed: %d\n", GetLastError());
return -3;
}
printf("Conhost handle: 0x%08X\n", proc);
CloseHandle(proc);
printf("Press a key to exit...\n");
c = getch();
return 0;
}
Output (as a VStudio 2010, Console App (Debug - x86) on Win 10):
e:\Work\Dev\StackOverflow\q035102238>ver
Microsoft Windows [Version 10.0.17134.48]
e:\Work\Dev\StackOverflow\q035102238>"Debug\q035102238.exe"
PID: 22388
Idx: 00 PID: 19892 PPID: 20164 Name: conhost.exe
Idx: 01 PID: 21128 PPID: 21120 Name: conhost.exe
Idx: 02 PID: 1144 PPID: 20572 Name: conhost.exe
Idx: 03 PID: 8184 PPID: 19572 Name: conhost.exe
Idx: 04 PID: 10976 PPID: 20608 Name: conhost.exe
Idx: 05 PID: 21284 PPID: 8792 Name: conhost.exe
Idx: 06 PID: 8172 PPID: 20444 Name: conhost.exe
Idx: 07 PID: 4396 PPID: 19484 Name: conhost.exe
Idx: 08 PID: 12484 PPID: 2580 Name: conhost.exe
Idx: 09 PID: 18636 PPID: 11552 Name: conhost.exe
Idx: 10 PID: 21456 PPID: 21016 Name: conhost.exe
Idx: 11 PID: 960 PPID: 3528 Name: conhost.exe
Idx: 12 PID: 20616 PPID: 18404 Name: conhost.exe
Idx: 13 PID: 21548 PPID: 21528 Name: conhost.exe
Idx: 14 PID: 20192 PPID: 8316 Name: conhost.exe
Idx: 15 PID: 2496 PPID: 9284 Name: conhost.exe
Idx: 16 PID: 5820 PPID: 23140 Name: conhost.exe
Idx: 17 PID: 6032 PPID: 26512 Name: conhost.exe
Connhost handle: 0x00000000
Press a key to exit...
So, it is possible to enumerate all running conhost.exe processes, and also get PROCESS_ALL_ACCESS to the one associated with my current application (I have to mention here that my Win user has full administrative privileges).
#EDIT0:
As #BladeMight noticed, on Win 7 all conhost.exe processes are children of crss.exe (as it can be also seen in ProcExp)
Output:
c:\Work\Dev\StackOverflow\q035102238>ver
Microsoft Windows [Version 6.1.7601]
c:\Work\Dev\StackOverflow\q035102238>q035102238.exe
PID: 1548
Idx: 00 PID: 4960 PPID: 3472 Name: conhost.exe
Idx: 01 PID: 5024 PPID: 3472 Name: conhost.exe
Idx: 02 PID: 5076 PPID: 3472 Name: conhost.exe
Idx: 03 PID: 2676 PPID: 3472 Name: conhost.exe
Idx: 04 PID: 1888 PPID: 3472 Name: conhost.exe
Connhost handle: 0x00000000
Press a key to exit...
One method that comes to mind is to obtain the start time of the CMD.EXE process. Then iterate through all of the CONHOST processes looking for the same (or very close) start time.
As a proof of concept download and install Process Explorer. Find your CMD.EXE process in ProcExp, then look at Properties, Image tab. Note the start time. Then look through each CONHOST process looking for one that starts at the same time.
Note that ProcExp displays 1 second resolution, but whatever underlying API ProcExp uses probably has better resolution.
You may need to google some to get an idea what API(s) ProcExp uses to gather the process start time. Additionally there are a variety of tools you can use to see what APIs an executable (ProcExp in this case) import. You may be able to deduce from the API names that ProcExp imports which one(s) would provide a process' start time.
Some unbelievably convoluted answers here. Use process explorer to get the pid of the console application and then do the following in kd -kl
lkd> !process 0n16592 0
Searching for Process with Cid == 40d0
Cid handle table at fffff8a001db8000 with 4368 entries in use
PROCESS fffffa8042eb9590
.
.
.
lkd> .process /P fffffa8042eb9590
Implicit process is now fffffa80`42eb9590
lkd> !peb
PEB at 000007fffffd3000
.
.
.
ProcessParameters: 0000000000202880
.
.
.
lkd> dt nt!_RTL_USER_PROCESS_PARAMETERS 0000000000202880
.
.
.
+0x010 ConsoleHandle : 0x00000000`00003d98 Void
+0x018 ConsoleFlags : 0
+0x020 StandardInput : 0x00000000`00000003 Void
+0x028 StandardOutput : 0x00000000`00000007 Void
+0x030 StandardError : 0x00000000`0000000b Void
.
.
.
.
lkd> ? 0x3d98
Evaluate expression: 15768 = 00000000`00003d98
This is the pid of the conhost process that it is attached to. In C++, you'd have to get the current PEB, take a look at how that is done programmatically here, study the structure of the PEB and ParameterBlock and then you'll know how to get the parameter block and at what offset it is in the parameter block. You can use the type definition for _PEB and _RTL_USER_PROCESS_PARAMETERS in winternl.h or the one here, or write your own using the ntkrnlmp.pdb symbols.
I'm using waitpid to get status code returned by the child when it changes state. I'm using:
if (WIFEXITED(code)){
if (WEXITSTATUS(code)==0){
//worked correctly
}
else{
//failed, throw error
}
}
else{
..
}
In the bottom part, I want to check for whether the child changed state without terminating and wait for it to terminate using a loop. How can I do so?
Assuming you don't ptrace the child process, you have to wait for it with the WUNTRACED and WCONTINUED flags:
waitpid(pid, &code, WUNTRACED | WCONTINUED);
If you do ptrace it, WUNTRACED is unnecessary, but since ptrace is a different kettle of fish altogether, I'll not go into it in detail.
Then, you can check what happened like so:
if (WIFEXITED(code)) {
// process ended normally with exit status WEXITSTATUS(code)
} else if(WIFSIGNALLED(code)) {
// process was terminated by signal WTERMSIG(code)
} else if(WIFSTOPPED(code)) {
// child was stopped by signal WSTOPSIG(code)
} else if(WIFCONTINUED(code)) {
// child was continued
}
To get a feeling for the way this works, you can play around with this piece of code:
#include <stddef.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if(pid == -1) {
fputs("fork failed\n", stderr);
} else if(pid == 0) {
int i;
for(i = 0; i < 100; ++i) {
usleep(1000000);
puts("child");
}
} else {
int status;
printf("%d\n", pid);
do {
waitpid(pid, &status, WUNTRACED | WCONTINUED);
printf("exited: %d status: %d\n"
"signalled: %d signal: %d\n"
"stopped: %d signal: %d\n"
"continued: %d\n",
WIFEXITED(status),
WEXITSTATUS(status),
WIFSIGNALED(status),
WTERMSIG(status),
WIFSTOPPED(status),
WSTOPSIG(status),
WIFCONTINUED(status));
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 0;
}
This will fork, the parent process will print the process ID of the child process, and when you send the child process signals, the parent will print the status properties it gets from waitpid (not all of them will make sense, naturally; if the process is stopped, WTERMSIG does not return anything meaningful). Here's my example output from a session in which I sent the child process SIGSTOP, SIGCONT, and SIGTERM:
38167
child
child
child
child
exited: 0 status: 19
signalled: 0 signal: 127
stopped: 1 signal: 19
continued: 0
exited: 0 status: 255
signalled: 0 signal: 127
stopped: 0 signal: 255
continued: 1
child
child
child
exited: 0 status: 0
signalled: 1 signal: 15
stopped: 0 signal: 0
continued: 0