跳到主要內容

記憶體管理-簡單的 shell

有了 fork() 和 exec(),我們可以實現簡單的 shell 了。目前只實現一種功能:讀取命令並執行之(如果命令存在的話)。



程式碼

kernel/main.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"


/*****************************************************************************
 *                               kernel_main
 *****************************************************************************/
/**
 * jmp from kernel.asm::_start.
 *
 *****************************************************************************/
PUBLIC int kernel_main()
{
 disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
   "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");

 int i, j, eflags, prio;
        u8  rpl;
        u8  priv; /* privilege */

 struct task * t;
 struct proc * p = proc_table;

 char * stk = task_stack + STACK_SIZE_TOTAL;

 for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++,t++) {
  if (i >= NR_TASKS + NR_NATIVE_PROCS) {
   p->p_flags = FREE_SLOT;
   continue;
  }

         if (i < NR_TASKS) {     /* TASK */
                        t = task_table + i;
                        priv = PRIVILEGE_TASK;
                        rpl     = RPL_TASK;
                        eflags  = 0x1202;/* IF=1, IOPL=1, bit 2 is always 1 */
   prio    = 15;
                }
                else {                  /* USER PROC */
                        t = user_proc_table + (i - NR_TASKS);
                        priv = PRIVILEGE_USER;
                        rpl     = RPL_USER;
                        eflags  = 0x202; /* IF=1, bit 2 is always 1 */
   prio    = 5;
                }

  strcpy(p->name, t->name); /* name of the process */
  p->p_parent = NO_TASK;

  if (strcmp(t->name, "INIT") != 0) {
   p->ldts[INDEX_LDT_C]  = gdt[SELECTOR_KERNEL_CS >> 3];
   p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3];

   /* change the DPLs */
   p->ldts[INDEX_LDT_C].attr1  = DA_C   | priv << 5;
   p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5;
  }
  else {  /* INIT process */
   unsigned int k_base;
   unsigned int k_limit;
   int ret = get_kernel_map(&k_base, &k_limit);
   assert(ret == 0);
   init_desc(&p->ldts[INDEX_LDT_C],
      0, /* bytes before the entry point
          * are useless (wasted) for the
          * INIT process, doesn't matter
          */
      (k_base + k_limit) >> LIMIT_4K_SHIFT,
      DA_32 | DA_LIMIT_4K | DA_C | priv << 5);

   init_desc(&p->ldts[INDEX_LDT_RW],
      0, /* bytes before the entry point
          * are useless (wasted) for the
          * INIT process, doesn't matter
          */
      (k_base + k_limit) >> LIMIT_4K_SHIFT,
      DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5);
  }

  p->regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl;
  p->regs.ds =
   p->regs.es =
   p->regs.fs =
   p->regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl;
  p->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
  p->regs.eip = (u32)t->initial_eip;
  p->regs.esp = (u32)stk;
  p->regs.eflags = eflags;

  p->ticks = p->priority = prio;

  p->p_flags = 0;
  p->p_msg = 0;
  p->p_recvfrom = NO_TASK;
  p->p_sendto = NO_TASK;
  p->has_int_msg = 0;
  p->q_sending = 0;
  p->next_sending = 0;

  for (j = 0; j < NR_FILES; j++)
   p->filp[j] = 0;

  stk -= t->stacksize;
 }

 k_reenter = 0;
 ticks = 0;

 p_proc_ready = proc_table;

 init_clock();
        init_keyboard();

 restart();

 while(1){}
}


/*****************************************************************************
 *                                get_ticks
 *****************************************************************************/
PUBLIC int get_ticks()
{
 MESSAGE msg;
 reset_msg(&msg);
 msg.type = GET_TICKS;
 send_recv(BOTH, TASK_SYS, &msg);
 return msg.RETVAL;
}


/**
 * @struct posix_tar_header
 * Borrowed from GNU `tar'
 */
struct posix_tar_header
{    /* byte offset */
 char name[100];  /*   0 */
 char mode[8];  /* 100 */
 char uid[8];  /* 108 */
 char gid[8];  /* 116 */
 char size[12];  /* 124 */
 char mtime[12];  /* 136 */
 char chksum[8];  /* 148 */
 char typeflag;  /* 156 */
 char linkname[100]; /* 157 */
 char magic[6];  /* 257 */
 char version[2]; /* 263 */
 char uname[32];  /* 265 */
 char gname[32];  /* 297 */
 char devmajor[8]; /* 329 */
 char devminor[8]; /* 337 */
 char prefix[155]; /* 345 */
 /* 500 */
};

/*****************************************************************************
 *                                untar
 *****************************************************************************/
/**
 * Extract the tar file and store them.
 *
 * @param filename The tar file.
 *****************************************************************************/
void untar(const char * filename)
{
 printf("[extract `%s'\n", filename);
 int fd = open(filename, O_RDWR);
 assert(fd != -1);

 char buf[SECTOR_SIZE * 16];
 int chunk = sizeof(buf);

 while (1) {
  read(fd, buf, SECTOR_SIZE);
  if (buf[0] == 0)
   break;

  struct posix_tar_header * phdr = (struct posix_tar_header *)buf;

  /* calculate the file size */
  char * p = phdr->size;
  int f_len = 0;
  while (*p)
   f_len = (f_len * 8) + (*p++ - '0'); /* octal */

  int bytes_left = f_len;
  int fdout = open(phdr->name, O_CREAT | O_RDWR);
  if (fdout == -1) {
   printf("    failed to extract file: %s\n", phdr->name);
   printf(" aborted]");
   return;
  }
  printf("    %s (%d bytes)\n", phdr->name, f_len);
  while (bytes_left) {
   int iobytes = min(chunk, bytes_left);
   read(fd, buf,
        ((iobytes - 1) / SECTOR_SIZE + 1) * SECTOR_SIZE);
   write(fdout, buf, iobytes);
   bytes_left -= iobytes;
  }
  close(fdout);
 }

 close(fd);

 printf(" done]\n");
}

/*****************************************************************************
 *                                Shabby Shell
 *****************************************************************************/
/**
 * A very very simple shell.
 *
 * @param tty_name TTY file name.
 *****************************************************************************/
void shabby_shell(const char * tty_name)
{
 int fd_stdin = open(tty_name, O_RDWR);
 assert(fd_stdin == 0);

 int fd_stdout = open(tty_name, O_RDWR);
 assert(fd_stdout == 1);

 char rdbuf[128];

 while (1) {
  write(1, "$ ", 2);
  int r = read(0, rdbuf, 70);
  rdbuf[r] = 0;

  int argc =0;
  char * argv[PROC_ORIGIN_STACK];
  char * p = rdbuf;
  char * s;

  int word = 0;
  char ch;
  do {
   ch = *p;
   if (*p != ' ' && *p != 0 && !word) {
    s = p;
    word = 1;
   }
   if ((*p == ' ' || *p == 0) && word) {
    word = 0;
    argv[argc++] = s;
    *p = 0;
   }
   p++;
  } while(ch);
  argv[argc] = 0;

  int fd = open(argv[0], O_RDWR);
  if (fd == -1) {
   if (rdbuf[0]) {
    write(1, "{", 1);
    write(1, rdbuf, r);
    write(1, "}\n", 2);
   }
  }
  else {
   close(fd);
   int pid = fork();
   if(pid != 0) { /* parent */
    int s;
    wait(&s);
   }
   else { /* child */
    execv(argv[0], argv);
   }
  }
 }

 close(1);
 close(0);
}

/*****************************************************************************
 *                                Init
 *****************************************************************************/
/**
 * The hen.
 *
 *****************************************************************************/
void Init()
{
 int fd_stdin  = open("/dev_tty0", O_RDWR);
 assert(fd_stdin  == 0);
 int fd_stdout = open("/dev_tty0", O_RDWR);
 assert(fd_stdout == 1);

 printf("Init() is running ...\n");

 /* extract `cmd.tar' */
 untar("/cmd.tar");

 char * tty_list[] = {"/dev_tty1", "/dev_tty2"};

 int i;
 for (i=0; i < sizeof(tty_list) / sizeof(tty_list[0]); i++) {
  int pid = fork();
  if (pid != 0) { /* parent process */
   printf("[parent is running, child pid:%d]\n", pid);
  }
  else { /* child process */
   printf("[child is running, pid:%d]\n", getpid());
   close(fd_stdin);
   close(fd_stdout);

   shabby_shell(tty_list[i]);
   assert(0);
  }
 }

 while (1) {
  int s;
  int child = wait(&s);
  printf("child (%d) exited with status: %d.\n", child, s);
 }

 assert(0);

}


/*======================================================================*
                               TestA
 *======================================================================*/
void TestA()
{
 for(;;);
}

/*======================================================================*
                               TestB
 *======================================================================*/
void TestB()
{
 for(;;);
}

/*======================================================================*
                               TestB
 *======================================================================*/
void TestC()
{
 for(;;);
}

/*****************************************************************************
 *                                panic
 *****************************************************************************/
PUBLIC void panic(const char *fmt, ...)
{
 int i;
 char buf[256];

 /* 4 is the size of fmt in the stack */
 va_list arg = (va_list)((char*)&fmt + 4);

 i = vsprintf(buf, fmt, arg);

 printl("%c !!panic!! %s", MAG_CH_PANIC, buf);

 /* should never arrive here */
 __asm__ __volatile__("ud2");
}
執行畫面

留言

這個網誌中的熱門文章

用 C# 批次控制 Word 合併列印

前由 我有全區的電話資料,問題在於我要依不同里別來製作出電話簿。結果如下圖: 單純採用合併列印無法達成我的需求。解決方法係用「功能變數」儲存上一個里別,與現在里別進行比較:若不同,則換頁。不過,這樣功能變數還蠻長的。最後,我還是採用 C# 來解決。 解決方案 用 C# 控制 WORD 中合併列印的「資料來源 Data Source」,給予不同里別的「sqlstatement」。迴圈處理不同的里別即可。但可預見其處理過程會很慢,不過還好,我可以不用在意它,有跑出結果即可。 程式碼 IList<string> areas = new List<string>() { "後壁", "侯伯", "嘉苳", "土溝", "嘉田", "嘉民", "菁豊", "崁頂", "後廍", "墨林", "菁寮", "新嘉", "頂長", "平安", "仕安", "竹新", "新東", "長安", "頂安", "福安", "烏樹" }; string root = @"D:\"; // 根目錄 string data = root + @"\data.docm"; // 資料檔(即資料來源) string template = root + @"\template.docx"; // 已設定好格式與合併欄位的 Word 檔 string output = @"d:\Final"; // 輸出之資料夾 object oMissing = System.Reflection.Missing.Va...

VLC c# 順利編譯

原文網址: http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 原文作者: haibindev 原文標題:c#万能视频播放器 本文的重點在於修正 class VlcPlayer,使其能順利在 VC# Express 2010 .Net Framework 4 下順利編譯。 修正重點在於 CallingConvention = CallingConvention. StdCall 改成 CallingConvention = CallingConvention. Cdecl using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace VlcDotNet { class VlcPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VlcPlayer(string pluginPath) { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); } public ...

[Symfony+Doctrine] 透過非 Id 來使用 Pessimistic Lock

根據 文件 ,Doctrine 有 Pessimistic Lock,又分為兩種: LockMode::PESSIMISTIC_WRITE:對應至 MySQL 的 Select FOR UPDATE LockMode::PESSIMISTIC_READ:對應至 MySQL 的 Select LOCK IN SHARE MODE 差別在於 LOCK IN SHARE MODE 會將在 row 的資料鎖定(row-level lock),在非同一交易(Transaction)下,不給寫入,其他交易可以讀取, 且可以繼續 Select LOCK IN SHARE MODE 。而 FOR UPDATE 不僅鎖定該資料,在非同一交易下,不給寫入,其它交易可以讀取, 但不能 Select LOCK IN SHARE MODE 。MySQL 文件有更詳細的比較與情境使用的說明,參考 網址 。 現在問題是,我們要完全採用 ORM 來處理資料。Doctrine 的文件提到 EntityManager::find 可以採用 Pessimistic Lock, 但 find 是透過 id 來處理 。而其他 find 系列函數(包括:findAll, findBy, findOneBy)皆不支援 LockMode。 因此,勢必要有方法來「透過非 id 來使用 Pessimistic Lock」。透過查看原始碼,簡單的方法是有的,解法之範例如下: 19 public function depositAction() 20 { 21 22 $em = $this->getDoctrine()->getManager(); 23 24 $em->transactional(function ($em) { 25 $entityName = 'AcmeTrainingBundle:Account'; 26 $lockMode = LockMode::PESSIMISTIC_READ; 27 $orderBy = null; 28 $...