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

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

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

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

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

1702閲覧

C言語のシグナルについて

strike1217

総合スコア651

C

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

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/07/24 14:46

編集2017/07/25 06:41

C/C++のシグナルについてなのですが・・・
シグナル (ソフトウェア)

UNIXやUnix系などのPOSIX準拠OSにおける限定的なプロセス間通信の一形態。プロセス間あるいはスレッド間で非同期イベントの発生を伝える機構である。

これって割り込みと何が違うんでしょうか??
わざわざ割り込みと区別してシグナルという概念を作り上げた理由は何でしょうか??
システムコールなどにも使用されるんでしょうか??

自分が一番知っているのは、killコマンドやCtrl+cを押した時に発行されるということです。
これ以外にも例外などに使用されるようです。
例外・割り込みとシグナルの違いがよくわかりません・・・

シグナルはハード割り込みであっても、プロセス間であっても必ずカーネルが介在するんですか??
しない場合があれば教えてください。

[実際に使う場面で不明な点]

[Linux シグナルの基礎](https://harasou.jp/2017/01/23/linux-signal/) [完了セマンティクス法](https://docs.oracle.com/cd/E19455-01/806-2732/gen-25/index.html) [sigemptyset() - 全シグナルを除外するためのシグナル・マスクの初期化](https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxbd00/rtsige.htm) **sigemptyset**この関数なんですが・・・ > すべてシグナルが選択されていない状態に初期化する > シグナル・セット set を、空集合に初期設定します。認識されたシグナルはすべて除外されます。 えーーと。つまりこの関数を実行するとすべてのシグナルは無視されるということでしょうか?? **sigaddset** その後、この関数によって登録されたシグナルのみを受け取るということで正しいでしょうか?? sigset_t sa_mask;とメンバ変数にシグナルマスクを代入できるように構造体が用意されています。 **このメンバ変数不要ですよね? sigempyset()によってsigaddset()のシグナル以外はすべて排除されるんで、なんでこんなメンバ変数を持つ必要があるんでしょうか?** 最後はこの関数です。 **siglongjmp** 近い関数として以下の説明を引用します。 > この関数は、jbuf に退避されていたレジスタ状態を復元し、プログラムを sigsetjmp() 部分から復帰させます (プログラムカウンタとスタックポインタも退避されています)。 ・・・? どういうことでしょうか?プログラムをsiglongjmp関数が呼ばれた地点から復帰するんですか?? 自分が実験したところこの関数が呼ばれたら終了したんですが・・・ ```ここに言語を入力 static sigjmp_buf return_point; siglongjmp(return_point, 1); ``` 第2パラメータが1だろうと0だろうと終了しますよね? [LONGJMP](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/longjmp.3.html) 使い方がよくわかりません。 どなたか教えてください。 gcc 64bit Linuxです。 「追記」参考サイト [シグナルの概念](http://linuxc.info/signal/signal1/) [非同期処理ってどういうこと?](http://qiita.com/kiyodori/items/da434d169755cbb20447) > シグナルはソフトウェア割り込みの実装の1つです。 Unixを作った先人達はこれら雑多な割り込みを抽象化しました。これがシグナルです。 ソフトウェア割り込みは、システムコールとシグナルの2つに分類されるということですかね? この2つ以外にもソフトウェア割り込みに属する概念ってあるんでしょうかね??

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

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

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

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

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

guest

回答4

0

ベストアンサー

これって割り込みと何が違うんでしょうか??
わざわざ割り込みと区別してシグナルという概念を作り上げた理由は何でしょうか??
例外・割り込みとシグナルの違いがよくわかりません・・・

割り込みや例外といった「ユーザプロセス実行とは非同期に生じるイベント」の扱いを抽象化したものが、「シグナル」です。安全なシグナルハンドラを実装するには ― C/C++セキュアコーディング入門 も参考に。

シグナルはハード割り込みであっても、プロセス間であっても必ずカーネルが介在するんですか??

シグナルハンドラはユーザスペースで実行されますから、おそらくカーネルの介在は必須だと思います。(たぶんね)

システムコールなどにも使用されるんでしょうか??

シグナルとシステムコールは無関係のはずです。シグナルは カーネルランド→ユーザスペース への非同期通知に対して、システムコールは ユーザスペース→カーネルランド への同期呼び出しです。


sigemptysetこの関数なんですが・・・
[...]
このメンバ変数不要ですよね? sigempyset()によってsigaddset()のシグナル以外はすべて排除されるんで、なんでこんなメンバ変数を持つ必要があるんでしょうか?

そもそも、シグナルセットの役割を誤解しているように思えます。シグナルセットは、複数種類が存在するシグナルに対して、“シグナルAを選択する/シグナルBは選択しない...”という部分集合を表現しているだけです。例)あるシグナルセット={シグナルA, シグナルC} という選択を表す。

質問文中のリンク先説明をもう一度ご確認ください。


最後はこの関数です。
siglongjmp

C標準ライブラリにある setjmp/longjmp関数 の動きを理解していないと、この関数の振る舞いも説明できません。詳細は longjmpと例外 を参照ください。

余談:setjmp/longjmpは「大域ジャンプ」と呼ばれる動きを実現しますが、C言語プログラムの構造を無視する飛び道具であり、安全に利用するのが難しい(JPCERT MSC22-C)関数です。強い理由が無ければ利用は控えてください。

投稿2017/07/25 05:27

編集2017/07/25 07:15
yohhoy

総合スコア6189

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

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

strike1217

2017/07/25 05:59 編集

sigemptyset シグナルセット・・・「このシグナルは処理する/このシグナルは無視する」とう状態の集合ですかね・・・ 無視するか処理するか両方共、空集合にするとうことでしょうか?
strike1217

2017/07/25 06:20

シグナルセットを空集合にするというのはすべて0にするということなので、すべてのシグナルを一旦拒否状態にしておくということで良いんですかね?
yohhoy

2017/07/25 07:17

回答中の用語選択が適切でなかったので、一部修正しました。シグナルセットは文字通り“シグナルの集合(set)”でしかありません。シグナルセット単体では、シグナルを無視するや処理するという概念は登場しえません。
strike1217

2017/07/25 07:17

「シグナルを選択する」とはどういう意味でしょうか??
yohhoy

2017/07/25 07:20

シグナルA, B, C, Dが存在するとき「シグナルセット={A, C}」では、シグナルA, Cが選択されており、シグナルB, Dは選択されてない。という意味です。集合に"含まれる"ことを、選択すると表現しました。 # 申し訳ありませんが、これ以上丁寧な説明は私にはできません。
strike1217

2017/07/25 07:25

ああ〜〜。なるほど! sigemptysetを実行すると空集合になるので、なんのシグナルも選択されていない状態になるわけですね!! シグナルがなにも選択されていないとどのような効果があるんですか? 選択されていないシグナルを拒否するかな・・・・と考えたんですが・・・
strike1217

2017/07/26 01:23

追記しました。 「ソフトウェア割り込みは、システムコールとシグナルの2つに分類されるということですかね? この2つ以外にもソフトウェア割り込みに属する概念ってあるんでしょうかね??」
guest

0

まずはじめに割り込みはハードウェアで提供する機能でシグナルはソフトウェアで提供する機能だということを理解してください。
ソフトウェア割り込みはソフトウェアで実装した割り込み相当の機能※という意味ではなくてCPU例外の一種です。
CPUを特権モードに移行するためにソフトウェア割り込みを発生させる必要があります。要はユーザー空間からカーネル空間に処理を移す際、すなわちシステムコールの実装でソフトウェア割り込みを使うということです。

(※ややこしいことに文脈によってはそう使うこともあります)

■シグナルと割り込みの区別
区別をしているわけではなくて、シグナルの機能実装に部分的に割り込みが使われているというだけです。

非同期な処理の通知を実現したいので割り込みを使うというのは正解の一つではありますが大変危険です。
OSはハードウェアの機能だとかリソースを隠蔽して(抽象化して)ユーザーに提供するべきです。
他のユーザーが割り込み内で無限ループさせたら他のユーザーが全く使えないということになってしまうのでOSが管理、監視をした上で
ハードウェアに依存することなく通知を実現する方法をユーザーに提供してるわけです。

■signalの動作

試しに以下のプログラムをstraceしながらSIGHUPを送ってやります。

C

1#include <signal.h> 2#include <stdio.h> 3 4void sigcatch(int); 5 6int main() { 7 if (SIG_ERR == signal(SIGHUP, sigcatch)) { 8 printf("failed to set signal handler.n"); 9 exit(1); 10 } 11 12 while (1) { 13 sleep(1); 14 } 15 16 return 0; 17} 18 19void sigcatch(int sig) { 20 printf("catch signal %dn", sig); 21} 22

kill -s 1 プロセスID

実行結果

rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({1, 0}, 0x7fffcedc5ae0) = 0 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({1, 0}, 0x7fffcedc5ae0) = 0 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({1, 0}, {0, 581633616}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal) --- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=31701, si_uid=1000} --- fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc64cf53000 rt_sigreturn() = -1 EINTR (Interrupted system call) rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 nanosleep({1, 0}, 0x7fffcedc5ae0) = ? +++ exited with 1 +++

nanosleep(sleep)で戻り値がERESTART_RESTARTBLOCKとなり、sigcatchが呼ばれています。
注目すべきことはシステムコールから復帰した後にシグナルハンドラが呼ばれている点です。

■実装
調べながら書いてますが、古い情報が混ざったり私の解釈が怪しい部分が多いので注意してください。

linux/kernel/signal.cにシグナルの実装が書かれています。
ソース内で頻繁にtask_structという構造体が出てきますが、プロセス、スレッドを記述したもので、この中にpending(個別保留中シグナルのキュー)、shared_pending(共有保留中シグナルのキュー)、sighand(シグナルハンドラ)、state(プロセスの状態)があります。

__send_signalでsignalをキューに入れた後、complete_signalを呼び出して、そこから最終的にwake_up_stateという関数呼び出してTASK_INTERRUPTIBLE(割り込み可能)のプロセスを起床させようとしています。このあとコンテキストが一旦切れますが、プロセスが起床してシステムコールからユーザーモードに戻る際に、do_notify_resumeでdo_signalが呼び出されキューに入っているシグナルを確認しています。シグナルがあった場合にはhandle_signalでシステムコールの戻り先をシグナルハンドラに書き換えて、システムコールから戻った際にシグナルハンドラが呼ばれます。その後再びシステムコールへ戻り通常の流れに戻るという仕組みのようです。

参考:
http://elixir.free-electrons.com/linux/latest/source/kernel/signal.c
http://elixir.free-electrons.com/linux/latest/source/arch/arm64/kernel/signal.c#L402
http://elixir.free-electrons.com/linux/latest/source/arch/arm64/kernel/signal.c#L331
http://elixir.free-electrons.com/linux/latest/source/arch/arm64/kernel/signal.c#L288

http://wiki.bit-hive.com/north/pg/%A5%B7%A5%B0%A5%CA%A5%EB
http://wiki.bit-hive.com/north/pg/%A5%B7%A5%B0%A5%CA%A5%EB%28%A4%BD%A4%CE2%29
http://wiki.bit-hive.com/north/pg/%A5%B7%A5%B0%A5%CA%A5%EB%28%A4%BD%A4%CE3%29
http://wiki.bit-hive.com/north/pg/%A5%B7%A5%B0%A5%CA%A5%EB(%A4%BD%A4%CE4)-%A5%B7%A5%B9%A5%C6%A5%E0%A5%B3%A1%BC%A5%EB%BA%C6%BC%C2%B9%D4(sleep)
https://github.com/hiboma/hiboma/blob/master/Linux%E3%82%AB%E3%83%BC%E3%83%8D%E3%83%AB%E8%A7%A3%E8%AA%AD%E5%AE%A4/Linux%E3%82%AB%E3%83%BC%E3%83%8D%E3%83%AB%E8%A7%A3%E8%AA%AD%E5%AE%A4-5-2.md#do_signal
http://d.hatena.ne.jp/cupnes/20150504/1430712820

投稿2017/07/26 04:32

nullbot

総合スコア910

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

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

strike1217

2017/07/26 04:53

な、なんと! とても丁寧なご説明ありがとうございます。 シグナルはソフトウェア割り込みの実装方法の1つだと書いてありました。(私の質問中のリンク先) ソフトウェア割り込みに分類される概念は、システムコールとシグナル以外に何がありますか? (この2つだけかな・・・?)
nullbot

2017/07/26 06:31

> シグナルはソフトウェア割り込みの実装方法の1つ Linuxアプリケーションの話の文脈で割り込みといったらシグナルのこと。 そうでない場合はCPU例外じゃないでしょうか。 ソフトウェアで割り込みに相当する機能を実現しているのはシグナルだけの話ではなくてスケジューラーがあっての話ですからシグナルはソフトウェア割り込みの実装方法の1つというのは色々と端折った言い方に思います。 またシステムコールとシグナルを並列に並べて書くのも違和感があります。 シグナルもシステムコールの一つです。man signalで探すとsignal(2)ですし。
strike1217

2017/07/26 07:01

なるほど・・・確かにそうですね。 signalを発行する際にカーネルに対してシステムコールを発行しているわけですしね・・・ 「そうでない場合はCPU例外じゃないでしょうか。」 つまり、システムコールは例外の方に属する・・・という意味でしょうか?
guest

0

sigemptyset()については

以下のように初期化しています。

sigset_t block; /* シグナルマスク */ sigemptyset( &block );
struct sigaction sact; sigemptyset(&sact.sa_mask);

シグナルセットを初期化しています。
てっきりこの状態で全てのシグナルを拒否するのかと考えていましたが、逆のようです。

ブロックしているシグナルは「シグナルマスク」というプロセス(正しくはスレッド)の属性で管理されています。

ブロックしたいシグナル = シグナルマスクと考えると・・・
シグナルマスクを空集合に初期化するということは、拒否するシグナルがない状態になるということではないでしょうか?

加えて、シグナルセット=空集合 ということは処理するシグナルも登録されいないことになります。

なので
拒否したいシグナルがあればその後、そのシグナルを別途登録する必要がある。
処理したいシグナルのあれば、そのシグナルを登録する必要がある。

処理するシグナル、拒否するシグナルどちらも登録されていない状態にするための関数だと思います。
(間違っていたらご指摘を!)

C言語のsigactionについての質問です

「追記」________
分かりやすいサイトを見つけました。
安全なシグナルハンドラの書き方

// シグナルマスク(ブロックするシグナルの集合)を初期化

sigemptyset(&block_mask);

この段階で、シグナルマスクを初期化しても拒否するわけではない・・・とのこと。
int test = 0; と同じようなものだと考えてよろしいかと・・・思います。

シグナルの使い方と実装について

Technology関連は用語が非常に紛らわしい・・・ですね。

投稿2017/07/26 05:20

編集2017/07/26 11:53
strike1217

総合スコア651

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

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

strike1217

2017/07/26 07:05

ん〜〜。 しかしこれでは、sigfillset(すべてシグナルが選択されている状態に初期化する)こちらの関数がまた意味不明になりそうですね〜〜〜 上記の説明では、sigfillset()は処理するシグナル、拒否するシグナル共に全て登録することを意味しているような・・・
guest

0

第2パラメータが1だろうと0だろうと終了しますよね?
LONGJMP
使い方がよくわかりません。

この一問だけで十分大きな問いであり、後回しにして構わない話です。yohhyさんが「強い理由が無ければ利用は控えてください」と仰る通り。基本レベルの事が分かっていない人に理解できないのは当然です。ある程度アセンブリ言語レベルの話ができるようでないと、漠然とした理解しかできないと思います。自分の作るプログラムで、どうしても必要になった時に考えればよろしい。

手当たり次第に質問するのは、勉強の仕方が悪いから。繰り返します、身の程知らずです。基本的なところから着実に積み上げるようにしないと。

投稿2017/07/25 23:47

rubato6809

総合スコア1380

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問