11.2. プロセスがマイグレートしない

助けてください。プロセス XYZ がマイグレートしません 下記で Moshe Bar 氏はなぜプロセスにマイグレートするもの、しないものが あるのかを説明しています。いつものように /proc/$pid/ を見る前に、 cantmoveを見てください。該当プロセスがなぜマイグレート できないのかわかるでしょう。

プロセスをロックすることもできますが、プロセスがロックされていないか どうかもチェックできます。
cat /proc/$PID/lock
$PID は問題のプロセスのプロセス ID です。

では、Moshe 氏自身がこの件について述べたことを挙げます。

よくあるのは、同じカーネルを使ってはいるが、RedHat と Debian が混在している といったようなディストリビューションに相違があるケースです。ディストリ ビューションが異なると、rc スクリプトが異なるやり方で openMosix を起動する 傾向にあります。 ある実装では /etc/inittab をすっかり書き換えてデーモンすべて(とその子供も)を
mosrun -h
で起動しています。 そのように起動するとマイグレートしません。 したがってプロセスを動かすと、これらのプロセスすべては /proc/pid/lock が 1 になります。強制的にマイグレートさせるためには、このファイルに 0 を記述 します。

それでは、下記の単純なプログラムをローカルの CPU 数より多く起動して、常に マイグレートさせてみましょう。2-way SMP システムでは、このプログラムを 3 回 起動し、クラスタ内にあるノードがローカルのシステムと似たような速度を持って いれば、マイグレートします。
int main() {
    unsigned int i;
    while (1) {
        i++;
    }
    return 0;
}
Pentium 800Mhz という CPU では、オーバーフローするまでに多少時間がかかります。

下記のような内容を持つサンプルプログラムは、決してマイグレートしません。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

...

key_t key; /* key to be passed to shmget() */
int shmflg; /* shmflg to be passed to shmget() */
int shmid; /* return value from shmget() */
int size; /* size to be passed to shmget() */

...

key = ...
size = ...
shmflg) = ...

if ((shmid = shmget (key, size, shmflg)) == -1) {
   perror("shmget: shmget failed"); exit(1); } else {
   (void) fprintf(stderr, "shmget: shmget returned %d\n", shmid);
   exit(0);
  }
...

下記のようなパイプを使ったプログラムは、うまくマイグレートします。

int pdes[2];

pipe(pdes);
if ( fork() == 0 )
  { /* child */
                                 close(pdes[1]); /* not required */
                                 read( pdes[0]); /* read from parent */
                                 .....
                 }
else
                 { close(pdes[0]); /* not required */
                                 write( pdes[1]); /* write to child */
                                 .....
                 }
pthread を使うように修正されたプログラムは、バージョン 2.4.17 からマイグレートはしませんが、segmentation fault はしなくなりました。
//
// Very simple program demonstrating the use of threads.
//
// Command-line argument is P (number of threads).
//
// Each thread writes "hello" message to standard output, with
//   no attempt to synchronize.  Output will likely be garbled.
//
#include <iostream>
#include <cstdlib>              // has exit(), etc.
#include <unistd.h>             // has usleep()
#include <pthread.h>            // has pthread_ routines

// declaration for function to be executed by each thread
void * printHello(void * threadArg);

// ---- Main program -------------------------------------------------

int main(int argc, char* argv[]) {

  if (argc < 2) {
    cerr << "Usage:  " << argv[0] << " numThreads\n";
    exit(EXIT_FAILURE);
  }
  int P = atoi(argv[1]);

  // Set up IDs for threads (need a separate variable for each
  //   since they're shared among threads).
  int * threadIDs = new int[P];
  for (int i = 0; i < P; ++i)
    threadIDs[i] = i;

  // Start P new threads, each with different ID.
  pthread_t * threads = new pthread_t[P];
  for (int i = 0; i < P; ++i)
    pthread_create(&threads[i], NULL, printHello,
                   (void *) &threadIDs[i]);

  // Wait for all threads to complete.
  for (int i = 0; i < P; ++i)
    pthread_join(threads[i], NULL);

  // Clean up and exit.
  delete [] threadIDs;
  delete [] threads;
  cout << "That's all, folks!\n";
  return EXIT_SUCCESS;
}

// ---- Code to be executed by each thread ---------------------------

// pre:  *threadArg is an integer "thread ID".
// post:  "hello" message printed to standard output.
//        return value is null pointer.
void * printHello(void * threadArg) {
  int * myID = (int *) threadArg;
  cout << "hello, world, ";
  // pointless pause, included to make the effects of
  //   synchronization (or lack thereof) more obvious
  usleep(10);
  cout << "from thread " << *myID << endl;
  pthread_exit((void* ) NULL);
}

プログラムがソケットを含む色々なファイルディスクリプタを使うと、マイグレート します(プロセスとともにソケットはマイグレートしませんが、oMFS や DFSA を使用 していればファイルはマイグレートされます)。

(上記のコードは Moshe 氏によるものです。Moshe Bar 氏個人によるもの、もしくは Qlusters, Inc. の CTO としての Moshe 氏のどちらかの立場です)。

openMosix の man も参照してください。プロセスがどうしてマイグレート しないかについて、それなりに説明してあります。

何らかの理由で、意図せずにプロセスがロックしたままになってしまった場合、 ロックされたプロセスをマイグレートするには、下記の記述を
# tell shells to allow subprocs to migrate to other nodes
echo 0 > /proc/self/lock
"/etc/profile" に単に追記するだけです。 注意:こうすると自分が望んだものだけでなく、すべての プロセスがマイグレート可能になります。特定のプロセスだけをマイグレート させたいなら「mosrun -l」を使ってマイグレートさせたいプロセスだけをさせて ください。