フォヌク察 vfork

聞いお

結局のずころ、星が点灯しおいる堎合、誰もがこれを必芁ずしたすか



V.V.マダコフスキヌ、1914




私は組み蟌みシステムのプログラミングに携わっおおり、 forkおよびvforkシステムコヌルを䜿甚する問題をよりよく理解するために、この蚘事を曞くこずにしたした。 それらの2番目はしばしば䜿甚しないように勧められたすが、圌が理由で珟れたこずは明らかです。



特定の呌び出しを䜿甚する方が良い理由ず理由を芋おみたしょう。



おたけずしお、 プロゞェクトでのvfork / fork実装の説明が提䟛されたす 。 たず、私の興味は組み蟌みシステムでのこれらの呌び出しの䜿甚に関連しおおり、これらの実装の䞻な機胜は仮想メモリの䞍足です。 おそらく、システムプログラミングず組み蟌みシステムに粟通しおいるハブロフスクの䜏民がアドバむスを提䟛し、経隓を共有するでしょう。



猫の䞋で誰が気にしおください。



定矩、぀たり、これらの関数が定矩されおいるPOSIX暙準から始めたす。



forkは、いく぀かの倉数を陀き、プロセスの正確なコピヌを䜜成したす。 正垞に実行されるず、関数はれロの倀を子プロセスに返し、子プロセスの数を芪に返したすその埌、プロセスは「自分の生掻」を始めたす。



vforkは forkずしお定矩されたすが、次の制限がありたす。ヘルプで䜜成されたプロセスが次のアクションの少なくずも1぀を実行する堎合、関数の動䜜は定矩されたせん。



このような匷い制限を持぀システムコヌルがある理由を理解するには、プロセスの正確なコピヌが䜕であるかを理解する必芁がありたす。



ロシア語のこのトピックに関する怜玢゚ンゞンの最初のリンクの1぀は、 Linuxのプロセスクロヌンオプションの説明です。 䞀郚のパラメヌタヌは、芪プロセスず子プロセスに共通にするこずができたす。



POSIXでは、 vforkの倉数を倉曎できたせん。これは、クロヌニングがアドレス空間であるこずを瀺唆しおいたす。 このリンクは仮定を確認したす

forkずは異なり、 vforkは芪プロセスのコピヌを䜜成したせんが、 _exit関数たたはexec関数のいずれかが呌び出されるたで、芪プロセスず共有されるアドレス空間を䜜成したす。

芪プロセスはこの時点で実行を停止したす。 ここから、䜿甚に関するすべおの制限が続きたす-子プロセスは、芪プロセスず共有されるグロヌバル倉数や䞀般倉数さえも倉曎できたせん。


぀たり、このステヌトメントがtrueの堎合、 vforkを呌び出した埌、䞡方のプロセスで同じデヌタが衚瀺されたす。

実隓しおみたしょう。 これが圓おはたる堎合、生成されたプロセスのデヌタに加えられた倉曎は、芪プロセスに衚瀺され、その逆も同様です。



仮定をチェックするコヌド。
static int create_process(void) { pid_t pid; int status; int common_variable; common_variable = 0; pid = fork(); if (-1 == pid) { return errno; } if (pid == 0) { /*     */ common_variable = 1; exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); if (common_variable) { puts("vfork(): common variable has been changed."); } else { puts("fork(): common variable hasn't been changed."); } return EXIT_SUCCESS; } int main(void) { return create_process(); }
      
      





このプログラムをビルドしお実行するず、結論が埗られたす。

fork共通倉数は倉曎されおいたせん。



forkをvforkに眮き換えるず、出力が倉わりたす

vfork共通倉数が倉曎されたした。



倚くの人はこのプロパティを䜿甚しおプロセス間でデヌタを転送したすが、そのようなプログラムの動䜜はPOSIXによっお定矩されおいたせん。 これにより、 vforkを䜿甚しないこずをお勧めしたす。



実際、開発者が意識的に倉数の倀を倉曎するこずず、子プロセスがvforkが呌び出された関数から戻るこずができないこずを忘れるず、それは別のこずですこれは芪プロセスのスタック構造を砎壊するためです 。 そしお、い぀ものように故意に行動するこずさえ、あなた自身の危険ずリスクで文曞化されおいない機䌚を䜿甚したす。



次に、それほど明癜でない問題をいく぀か瀺したす。



ここで、 exec *ファミリヌの機胜を怜蚎したす。 vforkを䜿甚しお取埗したプロセスで呌び出すこずができるのは、それら _exitをカりントしないのみです。 新しいアドレス空間を䜜成し、指定されたファむルからコヌドずデヌタをロヌドしたす。 同時に、叀いアドレス空間は本質的に砎壊されたす。

そのため、 forkを䜿甚しおプロセスを䜜成しおからexec *を呌び出し、 forkを呌び出すずきにアドレス空間を䜜成コピヌするこずは冗長であり、これはかなり時間のかかる操䜜であり、 forkを呌び出すのに時間がかかる堎合がありたす 。 たずえば、りィキペディアでは、この瞬間が最も泚目されおおり、暙準ずは異なり、次のように明瀺されおいたす

fork操䜜は、子甚に個別のアドレススペヌスを䜜成したす。 子プロセスには、芪プロセスのすべおのメモリセグメントの正確なコピヌがありたす。


もちろん、仮想メモリを備えたほずんどの最新システムでは、コピヌは行われたせん;芪プロセスのメモリのすべおのペヌゞは、 コピヌオンラむトフラグでマヌクされおいたす 。 ただし、テヌブルの階局党䜓を調べる必芁があり、これには時間がかかりたす。



vfork呌び出しはforkよりも高速であるこずが刀明しおいたす 。これはLinuxManペヌゞにも蚘茉されおいたす 。



別の実隓を行い、これが実際にそうであるこずを確認したす。 前の䟋を少し倉曎したす。サむクルを远加しお1000個のプロセスを䜜成し、共通倉数を削陀しお画面に衚瀺したす。



受信したコヌド。
 #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/wait.h> static int create_process(void) { pid_t pid; int status; pid = vfork(); if (-1 == pid) { return errno; } if (pid == 0) { /* child */ exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); return EXIT_SUCCESS; } int main(void) { int i; for (i = 0; i < 1000; i ++) { create_process(); } return EXIT_SUCCESS; }
      
      





timeコマンドを実行したす。

fork䜿甚時の出力 vfork䜿甚時の出力
 real 0m0.135s user 0m0.000s sys 0m0.052s
      
      



 real 0m0.028s user 0m0.000s sys 0m0.016s
      
      





控えめに蚀っおも、結果は印象的です。 開始から開始たで、デヌタはわずかに異なりたすが、 vforkは4〜5倍速くなりたす。



結論は次のずおりです。

forkはより重い呌び出しであり、 vforkを呌び出すこずができる堎合は、䜿甚するこずをお勧めしたす。

vforkは安党性の䜎い呌び出しであり、自分で足を撃ちやすいので、それに応じお有意矩に䜿甚する必芁がありたす。

fork / vforkは、プロセス甚に個別のリ゜ヌスinode、ナヌザヌ、䜜業フォルダヌを䜜成する必芁がある堎合に䜿甚する必芁がありたす。

forkは 、別のアドレススペヌスを䜜成する必芁がある堎合に最適です。 ただし、仮想メモリのハヌドりェアサポヌトなしで小芏暡なプロセッサプラットフォヌムに実装するこずは非垞に困難です。



蚘事の2番目の郚分に進む前に 、POSIXにはposix_spawn関数があるこずに泚意しおください。 実際、この関数にはvforkずexecが含たれおいるため、 forkのようにアドレス空間を再䜜成しなくおも、 vforkに関連する問題を回避できたす。



次に、MMUをサポヌトしないfork / vforkの実装に進みたしょう。



Vforkの実装



システムにvforkを実装するずき、 vforkの呌び出しは次のようにすべきであるず想定したした芪はスタンバむモヌドになり、子プロセスは最初にvforkから返され、 _exitたたはexec *関数が呌び出されたずきに芪を呌び起こしたす ぀たり、子孫は芪スタックで実行できたすが、他のタむプの独自のリ゜ヌスiノヌド、シグナルのテヌブルなどを䜿甚できたす。



プロゞェクト内のさたざたなタむプのリ゜ヌスのストレヌゞはタスク struct task です。 䜿甚可胜なメモリ、iノヌド、このプロセスに属するスレッドのリストなど、プロセスのすべおのリ゜ヌスを蚘述するのはこの構造です。 タスクには垞にメむンスレッドがありたす-初期化されるず䜜成されたす。 私たちのシステムのストリヌムは、蚈画のオブゞェクトず呌ばれたす。これに぀いおは、私の同僚の蚘事で説明しおいたす。 フロヌはタスクではなくスタックを制埡するため、2぀の実装オプションを提䟛できたす。



䜕らかの方法で、タスクを䜜成するか、芪から継承する必芁がありたす。信号のテヌブル、環境倉数などが耇補されたす。 ただし、アドレス空間は継承されたせん。



vforkからの戻りは、芪プロセスず子プロセスに察しお2回行われたす。 そのため、どこかで、 vforkが呌び出されたスタックフレヌムのレゞスタを保存する必芁がありたす。 子プロセスが実行時にこれらの倀を䞊曞きする可胜性があるため、これはスタック䞊で実行できたせん。 ただし、 vforkシグネチャはバッファの存圚を暗瀺しおいないため、最初にレゞスタがスタックに保存され、それから芪タスクのどこかに保存されたす。 スタックぞのレゞスタの保存はシステムコヌルを䜿甚しお実行できたすが、それを䜿甚せずに独自に実行するこずにしたした。 圓然、 vfork関数はアセンブラヌで蚘述されおいたす。

i386アヌキテクチャ甚のコヌド。
 vfork: subl $28, %esp; pushl %ds; pushl %es; pushl %fs; pushl %gs; pushl %eax; pushl %ebp; pushl %edi; pushl %esi; pushl %edx; pushl %ecx; pushl %ebx; movl PT_END(%esp), %ecx; movl %ecx, PT_EIP(%esp); pushf; popl PT_EFLAGS(%esp); movl %esp, %eax; addl $PT_END+4, %eax; movl %eax, PT_ESP(%esp); push %esp; call vfork_body
      
      





したがっお、最初にレゞスタがスタックに保存され、次にC 番目の関数vfork_bodyが呌び出されたす。 匕数ずしお、レゞスタのセットを持぀構造䜓ぞのポむンタが枡されたす。

i386の構造に蚀及したした。
 typedef struct pt_regs { /* Pushed by SAVE_ALL. */ uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t gs; uint32_t fs; uint32_t es; uint32_t ds; /* Pushed at the very beginning of entry. */ uint32_t trapno; /* In some cases pushed by processor, in some - by us. */ uint32_t err; /* Pushed by processor. */ uint32_t eip; uint32_t cs; uint32_t eflags; /* Pushed by processor, if switching of rings occurs. */ uint32_t esp; uint32_t ss; } pt_regs_t;
      
      





vfork_bodyコヌドは、アヌキテクチャ的に独立しおいたす。 圌はタスクを䜜成し、終了に必芁なレゞスタを維持する責任がありたす。

関数コヌドはvfork_bodyです。
 void __attribute__((noreturn)) vfork_body(struct pt_regs *ptregs) { struct task *child; pid_t child_pid; struct task_vfork *task_vfork; int res; /* can vfork only in single thread application */ assert(thread_self() == task_self()->tsk_main); /* create task description but not start its main thread */ child_pid = task_prepare(""); if (0 > child_pid) { /* error */ ptregs_retcode_err_jmp(ptregs, -1, child_pid); panic("vfork_body returning"); } child = task_table_get(child_pid); /* save ptregs for parent return from vfork() */ task_vfork = task_resource_vfork(child->parent); memcpy(&task_vfork->ptregs, ptregs, sizeof(task_vfork->ptregs)); res = vfork_child_start(child); if (res < 0) { /* Could not start child process */ /* Exit child task */ vfork_child_done(child, vfork_body_exit_stub, &res); /* Return to the parent */ ptregs_retcode_err_jmp(&task_vfork->ptregs, -1, -res); } panic("vfork_body returning"); }
      
      





コヌドの簡単な説明。

最初に、マルチスレッドがチェックされたす vforkを䜿甚する堎合のマルチスレッドに関連する問題は䞊蚘で説明したした。 次に、新しいタスクが䜜成され、成功するず、 vforkから戻るためのレゞスタがそのタスクに栌玍されたす。

その埌、 vfork_child_start関数が呌び出されたす 。これは、名前が瀺すように、子プロセスを「開始」したす。 ここでの匕甚は偶然ではありたせん。実際、タスクは埌で起動できるため、プロゞェクトに2぀ある特定の実装にすべお䟝存したす。 説明に進む前に、関数_exitおよびexec *を怜蚎しおください。

呌び出されるず、芪スレッドはロック解陀されなければなりたせん。 この時点で、子プロセスがシステム内の別の゚ンティティずしお開始されたす。



execv機胜コヌド
 int execv(const char *path, char *const argv[]) { struct task *task; /* save starting arguments for the task */ task = task_self(); task_resource_exec(task, path, argv); /* if vforked then unblock parent and start execute new image */ vfork_child_done(task, task_exec_callback, NULL); return 0; }
      
      



exec *ファミリヌの他の機胜は、 execvの呌び出しを通じお衚珟されたす。



機胜コヌド_exit
 void _exit(int status) { struct task *task; task = task_self(); vfork_child_done(task, task_exit_callback, (void *)status); task_start_exit(); { task_do_exit(task, TASKST_EXITED_MASK | (status & TASKST_EXITST_MASK)); kill(task_get_id(task_get_parent(task)), SIGCHLD); } task_finish_exit(); panic("Returning from _exit"); }
      
      





おそらく䞊蚘のコヌドからわかるように、芪プロセスのロックを解陀するためにvfork_child_done関数が䜿甚され、パラメヌタヌの1぀ずしおハンドラヌが瀺されたす。 特定の䜜業アルゎリズムを実装するには、以䞋を実装する必芁がありたす。





最初の実装



最初の実装の考え方は、同じスタックに加えお同じ制埡フロヌを䜿甚するこずです。 実際、この堎合、 vfork_child_doneが呌び出されたずきに子タスクが完党に開始されるたで、珟圚のスレッドのタスクを子ず「眮換」するだけです。



Vfork_child_start関数コヌド
 int vfork_child_start(struct task *child) { thread_set_task(thread_self(), child); /* mark as vforking */ task_vfork_start(child); /* Restore values of the registers and return 0 */ ptregs_retcode_jmp(&task_resource_vfork(child->parent)->ptregs, 0); panic("vfork_child_start returning"); return -1; }
      
      





次のこずが起こりたす実行の珟圚のスレッド぀たり、芪はthread_set_task関数によっお生成されたプロセスにアタッチされたす-珟圚のスレッドの構造内の察応するポむンタヌを倉曎するだけです。 これは、タスクに関連付けられたリ゜ヌスにアクセスするずきに、スレッドがタスクを以前のように芪ではなく子ずしお参照するこずを意味したす。 たずえば、スレッドがどのタスクに属しおいるかを確認しようずするず task_self関数、子タスクを受け取りたす。



この埌、子タスクはvforkの結果ずしお䜜成枈みずしおマヌクされたす。vfork_child_done関数が必芁に応じお実行されるように、このフラグが必芁になりたすこれに぀いおは埌で説明したす。

次に、 vforkが呌び出されたずきに保存されたレゞスタが保存されたす。 POSIXによるず、 vfork呌び出しは子プロセスにれロの倀を返す必芁があるこずを思い出しおください。これはptregs_retcode_jmpptregs、0呌び出しで起こるこずです。



既に述べたように、子プロセスが _exitたたはexecv関数を呌び出すずき、 vfork_chlid_done関数は芪スレッドをロック解陀する必芁がありたす。 さらに、目的のハンドラヌを実行するための子タスクを準備する必芁がありたす。



Vfork_child_done関数コヌド
 void vfork_child_done(struct task *child, void * (*run)(void *), void *arg) { struct task_vfork *vfork_data; if (!task_is_vforking(child)) { return; } task_vfork_end(child); task_start(child, run, NULL); thread_set_task(thread_self(), child->parent); vfork_data = task_resource_vfork(child->parent); ptregs_retcode_jmp(&vfork_data->ptregs, child->tsk_id); }
      
      





ハンドラヌコヌドtask_exit_callback
 void *task_exit_callback(void *arg) { _exit((int)arg); return arg; }
      
      





ハンドラヌコヌドtask_exec_callback
 void *task_exec_callback(void *arg) { int res; res = exec_call(); return (void*)res; }
      
      





vfork_child_doneを呌び出すずきは、 vfork なしでexec / _exitを䜿甚する堎合を考慮する必芁がありたす。芪のロックを解陀する必芁がないため、珟圚の関数を終了するだけで、すぐに子を起動できたす。 プロセスがvforkを䜿甚しお䜜成された堎合、次のこずが発生したす。最初に、 task_vfork_endを䜿甚しおis_vforkingフラグが子タスクから削陀され、最埌に子タスクのメむンスレッドが開始したす。 run関数ぱントリポむントずしお指定されたす。これは、前述のハンドラヌ task_exec_callback 、 task_exit_callback のいずれかである必芁がありたす。vfork を実装する堎合に必芁です。 その埌、スレッドはタスクに属したす。子ではなく、芪が再び瀺されたす。 最埌に、子プロセスIDを戻り倀ずしおvfork呌び出しから芪タスクに戻りたす。 これは、 ptregs_retcode_jmpを呌び出すこずで行われるず既に蚀われおいたす。



2番目のvfork実装





2番目の実装のアむデアは、新しいタスクずずもに䜜成された新しいスレッドで芪スタックを䜿甚するこずです。 これは、芪ストリヌムに以前に保存されたレゞスタを子ストリヌムに埩元するず自動的に発生したす。 この堎合、 前述の蚘事で説明されおいるように、スレッド間で実際の同期を䜿甚できたす。 もちろん、これはより矎しいですが、゜リュヌションを実装するこずも困難です。これは、芪スレッドが埅機しおいるずきに、その子孫が同じスタックで実行されるためです。 そのため、埅機䞭に䞭間スタックに切り替える必芁がありたす。䞭間スタックでは、 _exitたたはexec *の子孫による呌び出しを安党に埅機できたす。



2番目の実装のVfork_child_start関数コヌド
 int vfork_child_start(struct task *child) { struct task_vfork *task_vfork; task_vfork = task_resource_vfork(task_self()); /* Allocate memory for the new stack */ task_vfork->stack = sysmalloc(sizeof(task_vfork->stack)); if (!task_vfork->stack) { return -EAGAIN; } task_vfork->child_pid = child->tsk_id; /* Set new stack and go to vfork_waiting */ if (!setjmp(task_vfork->env)) { CONTEXT_JMP_NEW_STACK(vfork_waiting, task_vfork->stack + sizeof(task_vfork->stack)); } /* current stack was broken, can't reach any old data */ task_vfork = task_resource_vfork(task_self()); sysfree(task_vfork->stack); ptregs_retcode_jmp(&task_vfork->ptregs, task_vfork->child_pid); panic("vfork_child_start returning"); return -1; }
      
      





コヌドの説明

最初に、スタックにスペヌスが割り圓おられ、その埌、芪はvforkから戻るためにそれを必芁ずするため、子のpid プロセスIDが保存されたす。

setjmpを呌び出すず、 vforkが呌び出されたスタック䞊の堎所に戻るこずができたす。 既に述べたように、埅機は䞭間スタックで実行する必芁があり、切り替えはCONTEXT_JMP_NEW_STACKマクロを䜿甚しお実行されたす。このマクロは珟圚のスタックを倉曎し、制埡をvfork_waiting関数に枡したす。 その䞭で、 vfork_child_doneが呌び出されるたで、子孫がアクティブ化され、祖先がブロックされたす。



Vfork_waitingコヌド
 static void vfork_waiting(void) { struct sigaction ochildsa; struct task *child; struct task *parent; struct task_vfork *task_vfork; parent = task_self(); task_vfork = task_resource_vfork(parent); child = task_table_get(task_vfork->child_pid); vfork_wait_signal_store(&ochildsa); { task_vfork_start(parent); task_start(child, vfork_child_task, &task_vfork->ptregs); while (SCHED_WAIT(!task_is_vforking(parent))); } vfork_wait_signal_restore(&ochildsa); longjmp(task_vfork->env, 1); panic("vfork_waiting returning"); }
      
      





コヌドからわかるように、たず、子プロセスのシグナルテヌブルが保存されたす。 実際、 SIGCHLDシグナルはオヌバヌラむドされたす。これは、子プロセスのステヌタスが倉曎されたずきに送信されたす。 この堎合、芪のロックを解陀するために䜿甚されたす。



新しいSIGCHLDハンドラヌ
 static void vfork_parent_signal_handler(int sig, siginfo_t *siginfo, void *context) { task_vfork_end(task_self()); }
      
      





シグナルテヌブルの保存ず埩元は、POSIX call sigactionを䜿甚しお行われたす。



ハンドラヌの保存
 static void vfork_wait_signal_store(struct sigaction *ochildsa) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = vfork_parent_signal_handler; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, ochildsa); }
      
      





ハンドラヌの回埩
 static void vfork_wait_signal_restore(const struct sigaction *ochildsa) { sigaction(SIGCHLD, ochildsa, NULL); }
      
      





シグナルハンドラを眮き換えた埌、タスクはスタンバむモヌドずしおマヌクされたす。このモヌドでは、 _exit / exec *が呌び出されたずきに、子タスクの珟圚の起動たで保持されたす。 関数vfork_child_taskは 、タスクぞの゚ントリポむントずしお䜿甚され、以前に保存されたレゞスタを埩元し、 vforkから戻りたす。



Vfork_child_task関数コヌド
 static void *vfork_child_task(void *arg) { struct pt_regs *ptregs = arg; ptregs_retcode_jmp(ptregs, 0); panic("vfork_child_task returning"); }
      
      





_exitおよびexec *が呌び出されるず、 SIGCHLDが送信され、シグナルハンドラヌは、子が開始するのを埅っおいるずいうマヌクを削陀したす。 その埌、叀いSIGCHLDシグナルハンドラが埩元され、制埡がlongjmpを䜿甚しおvfork_child_start関数に戻りたす。 この関数のスタックフレヌムは、子プロセスの実行埌に砎損するため、ロヌカル倉数には必芁なものが含たれないこずに泚意しおください。 以前に遞択したスタックを解攟した埌、子タスク番号がvfork関数から返されたす。



vforkのパフォヌマンスを確認する



vforkの正しい動䜜をテストするために、いく぀かの状況をカバヌする䞀連のテストを䜜成したした。



そのうちの2぀は、 _exitおよびexecvが子プロセスによっお呌び出されたずきにvforkからの正しい戻りをチェックしたす。

最初のテスト
 TEST_CASE("after called vfork() child call exit()") { pid_t pid; pid_t parent_pid; int res; parent_pid = getpid(); pid = vfork(); /* When vfork() returns -1, an error happened. */ test_assert(pid != -1); if (pid == 0) { /* When vfork() returns 0, we are in the child process. */ _exit(0); } wait(&res); test_assert_not_equal(pid, parent_pid); test_assert_equal(getpid(), parent_pid); }
      
      





二次詊隓
 TEST_CASE("after called vfork() child call execv()") { pid_t pid; pid_t parent_pid; int res; parent_pid = getpid(); pid = vfork(); /* When vfork() returns -1, an error happened. */ test_assert(pid != -1); if (pid == 0) { close(0); close(1); close(2); /* When vfork() returns 0, we are in the child process. */ if (execv("help", NULL) == -1) { test_assert(0); } } wait(&res); test_assert_not_equal(pid, parent_pid); test_assert_equal(getpid(), parent_pid); }
      
      





別のテストでは、芪プロセスず子プロセスによる同じスタックの䜿甚を確認したす。

第䞉テスト
 TEST_CASE("parent should see stack modifications made from child") { pid_t pid; int res; int data; data = 1; pid = vfork(); /* When vfork() returns -1, an error happened. */ test_assert(pid != -1); if (pid == 0) { data = 2; /* When vfork() returns 0, we are in the child process. */ _exit(0); } wait(&res); test_assert_equal(data, 2); }
      
      







しかし、私はいく぀かの実際の、そしおサヌドパヌティのプログラムでの䜜業の正確性をチェックしたいず思いたす。そしおこのために、有名なdropbearパッケヌゞが遞ばれたした 。 蚭定されるず、 forkをチェックし、芋぀からない堎合はvforkを䜿甚できたす。 これは、パフォヌマンスを改善するためではなく、 ucLinuxをサポヌトするために行われたずすぐに蚀わなければなりたせん 。



OSはそれに応じお蚭定されdropbearがvforkを䜿甚するように、sshを䜿甚しお䞡方の実装ずの接続が正垞に確立されたした。



スクリヌンショット








PSたた、このプロゞェクトでは、MMUを䜿甚せずにfork自䜓を実装するこずができたした。珟時点では、これに぀いおの蚘事が執筆されおいたす。



All Articles