質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

2391閲覧

自作シェルでシグナルハンドラを使ってpsコマンドを自作したい

ijuya_yika

総合スコア50

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2017/11/19 17:58

編集2017/11/20 01:56

###前提・実現したいこと
C言語の自作シェル内でシグナルハンドラを使って自作psコマンド(現在動いているプロセスのIDを表示するという簡単な関数)を作成したい

###発生している問題・エラーメッセージ
<コード訂正後>
removeProcessarr_pid配列のプロセスIDが子プロセス終了後-1に書き換えが行われない => 今まで行った全てのプロセスのプロセスIDが表示されてしまう

<コード訂正前>
(1)HELP1で子プロセスを配列に格納する際に親プロセスと同じプロセスIDが格納されてしまう
(2)HELP2でセグメンテーション違反が起こる
=>指摘を受けポインタを使いまわすのをやめる&int型ポインタの配列をint型配列に変更後し解決

###該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <string.h> 5#include <sys/wait.h> 6#include <errno.h> 7#define S 1000 8 9int arr_pid[S] = {}; /* ここにプロセスが呼ばれる度新しいプロセスIDを登録 */ 10 11void removeProcess(int signal){ 12 pid_t pid; 13 while((pid = waitpid(-1, NULL, WNOHANG)) > 0){ 14 /* 子プロセスが終了したら子プロセスのPIDを-1に変える */ 15 for(int i=0; arr_pid[i] != 0; ++i){ /** HELP2 **/ 16 if(arr_pid[i] == signal){ 17 arr_pid[i] = -1; 18 } 19 } 20 } 21} 22 23void printProcess(){ 24 int i; 25 for(i=0; arr_pid[i] != 0; ++i){ 26 if(arr_pid[i] != -1){ 27 printf("PID: %d\n", arr_pid[i]); 28 } 29 } 30} 31 32int main(int argc, char *argv[]){ 33 char* token[S]; 34 char* eof; 35 char* and; 36 char usrin[S]; 37 int pid, status, count, num_p = 0; 38 39 40 pid = getpid(); 41 arr_pid[num_p++]= pid; /* 親プロセスのプロセスIDを取得しarr_pidに入れる */ 42 signal(SIGCHLD, &removeProcess); /* 子プロセスが終了=>SIGCHLDシグナルが送られる度配列に入れたプロセスIDを-1に変更 */ 43 44 while(1){ 45 printf(">>"); 46 eof = fgets(usrin, sizeof(usrin), stdin); 47 48 if(eof==NULL) 49 exit(0); 50 51 usrin[strlen(usrin)-1] = '\0'; 52 and = strchr(usrin, '&'); 53 54 token[0] = strtok(usrin, " "); 55 for(count=1; count<S; ++count){ 56 token[count] = strtok(NULL, " "); 57 if(token[count]==NULL) 58 break; 59 } 60 61 /* 入力がmy_psなrプロセスを出力 */ 62 if((strcmp(token[0], "my_ps")==0)){ 63 printProcess(); 64 } else { 65 /* my_ps 以外なら入力されたコマンドを実行 */ 66 pid = fork(); 67 68 69 if(pid==-1) 70 exit(-1); 71 else if(pid==0){ 72 if(execvp(token[0], token)<0){ 73 printf("エラー : %s\n", strerror(errno)); 74 exit(1); 75 } 76 } else { 77 /* 子プロセスのプロセスIDを配列に格納 */ 78 arr_pid[num_p++] = pid; 79 if(and==NULL) 80 wait(&status); 81 82 } 83 } 84 } 85 86 return 0; 87}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

システムコールを用いて取得したいということでしょうか。
質問にOSの記載がないため参考になるかはわかりませんが、
Linux等であれば、/procを参照することでプロセスの情報を取得することもできます。

text

1$ cat /proc/7163/status 2Name: ntpd 3State: S (sleeping) 4Tgid: 7163 5Ngid: 0 6Pid: 7163 7PPid: 1 8TracerPid: 0 9Uid: 108 108 108 108 10Gid: 114 114 114 114 11FDSize: 64 12Groups: 114 13NStgid: 7163 14NSpid: 7163 15NSpgid: 7163 16NSsid: 7163 17VmPeak: 171336 kB 18VmSize: 112092 kB 19VmLck: 0 kB 20VmPin: 0 kB 21VmHWM: 5088 kB 22VmRSS: 368 kB 23VmData: 74456 kB 24VmStk: 132 kB 25VmExe: 684 kB 26VmLib: 5812 kB 27VmPTE: 104 kB 28VmPMD: 12 kB 29VmSwap: 308 kB 30HugetlbPages: 0 kB 31Threads: 1 32SigQ: 0/63511 33SigPnd: 0000000000000000 34ShdPnd: 0000000000000000 35SigBlk: 0000000000000000 36SigIgn: 0000000000001000 37SigCgt: 0000000180006a47 38CapInh: 0000000000000000 39CapPrm: 0000000002000400 40CapEff: 0000000002000400 41CapBnd: 0000003fffffffff 42CapAmb: 0000000000000000 43Seccomp: 0 44Cpus_allowed: f 45Cpus_allowed_list: 0-3 46Mems_allowed: 00000000,00000001 47Mems_allowed_list: 0 48voluntary_ctxt_switches: 5576843 49nonvoluntary_ctxt_switches: 3409

投稿2017/11/19 21:31

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ijuya_yika

2017/11/19 23:12

質問を訂正しました。システムハンドラを使って子プロセスIDを管理するようにしたいです。
退会済みユーザー

退会済みユーザー

2017/11/19 23:18

forkの結果としてpidを取得していますが、getpidの値で上書きしているように見えます。
ijuya_yika

2017/11/19 23:53

コードを訂正したのですが頂いたコメントを上手く反映できているでしょうか。 main直後のpid = getpid();でシェルのプロセスIDを取得し格納、pid=fork()後に親プロセスには子プロセスのプロセスIDが戻る為 pid = getpidとせずそのままarr_pid[num_p++] = &pid;としてみました。ただこれでも同じプロセスIDがarr_pid[0] arr_pid[1]に入ってしまいます
退会済みユーザー

退会済みユーザー

2017/11/20 00:16 編集

pidはなぜ&で参照しているのでしょうか。 ローカル変数をポインタ参照しているため、解放された後に使い回されているのでないかと推測します。 大変危険なコードだと考えます。 追記: そもそもこのコードだと使い回し等関係なく常に同じアドレスしか返りませんね。
ijuya_yika

2017/11/20 00:49 編集

int* arr_pid[S] = {NULL}; ← int型のポインタの配列にプロセスIDを指したポインタを格納したかったので&で参照しています。 ご指摘頂いたとおりポインタを使いまわしていた為、新たにpid_t temp = getpid(); arr_pid[num_p++] = &temp;と変更後、常に同じアドレスが格納されてしまう問題を解決できました。
退会済みユーザー

退会済みユーザー

2017/11/20 01:13 編集

やりたいことは下記ではないですか? *arr_pid[num_p++] = pid;
ijuya_yika

2017/11/20 01:18

*arr_pid[num_p++] = pid;だとセグメンテーション違反になります。 初期化した時にarr_pidはNULLで埋まっているのが原因だと思います。
退会済みユーザー

退会済みユーザー

2017/11/20 01:21 編集

int* arr_pid[S] = {}; を int arr_pid[S] = {}; にすれば arr_pid[num_p++] = pid; とできるかと思います。
ijuya_yika

2017/11/20 01:30

コメントありがとうございます。 よくよく考えたらint型ポインタの配列にするメリットが1つも無かったのに今気づきました。 int型のポインタへコードを修正しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問