一垄青竹映陋室,半枝桃花衬碧窗.

Monday, August 20, 2007

How to setup up tftp and nfs environment on FC6

<#DocByCoryXie#>
This document describes the simple steps needed to setup tftp and nfs
environment for cross developemnt.
1.yum install tftp
2.yum install tftp-server
3.vi /etc/xinetd.d/tftp and change "disable = yes" to "disable = no"

# default: off
# description: The tftp server serves files using the trivial file transfer \
# protocol. The tftp protocol is often used to boot diskless \
# workstations, download configuration files to network-aware printers, \
# and to start the installation process for some operating systems.
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -c -s /tftpboot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
4./etc/rc.d/init.d/xinetd restart
5.vi /etx/exports
/opt/montavista/pro/devkit/arm/v5t_le/target *(rw,no_root_squash)
6./etc/rc.d/init.d/nfs restart
7.test tftp server,create a file in /tftpboot,then use
tftp to login to the server and get that file.
#tftp 10.136.4.40
#>get hello.txt
8.test NFS server,must use
#iptables -F
#mount -t nfs 10.136.4.40:/opt/montavista/pro/devkit/arm/v5t_le/target /mnt/cdrom
#cd /mnt/cdrom
#ls
<#/DocByCoryXie#>

How to install MontaVista Linux on FC6

<#DocByCoryXie#>
This document shows the steps need to install Montavista Linux Pro 4.0 Tools
on FC6,and possible other host which was not nativly compiled for by MontaVista.

1.Generate correct host file
At first ,the installer wants to use the supported_hosts file for
a configuration for waht it has been compiled,we need to change it for our new
host.

##### Identify host based on default if the user has not overridden.
if [ -z "$HOST_FILE" ]; then
mv_host=`identify_host "$media_install/install-components/cross-control/data/supported_hosts"`
else
mv_host=`identify_host "$HOST_FILE"`
fi

Thus we should write a file,such as '/mnt/hosts',
and instert what it need for our new host.
The host file format comes from:

# This table lists the criteria to identify a host and map it to our
# directory stucture:
#
# ::::mapping
#
Linux:i.*86:cat /etc/redhat-release:Red Hat Linux release 9 (Shrike):redhat90

so we need to use these commands to generate what we need,for my system FC6,it gives

Linux:i.*86:cat /etc/fedora-release:Fedora Core release 6 (Zod):redhat90

fill the line above into /mnt/hosts

and
#export HOST_FILE=/mnt/hosts
#/mnt/cdrom/install

2.Update host system with old libstdc++-33
Then you will be prompted this error:
mvl-inst-eng: error while loading shared libraries: libstdc++.so.5:
cannot open shared object file: No such file or directory

now you need to install compat-libstdc++-33.

yum install compat-libstdc++-33

please also :

#yum install libXp

because the last step will need this libXp.so.6.

3.mount ISO images
#mount -t iso9660 /mnt/hgfs/Tools/mvl_host_binaries.iso /mnt/cdrom -o loop
#/mnt/cdrom/install
http://127.0.0.1:9999
follow instructions to do "Next"
#mount -t iso9660 /mnt/hgfs/Tools/mvl_target_binaries.iso /mnt/cdrom -o loop

depends on what way you want to install,you may need to use:
#mount -t iso9660 /mnt/hgfs/Tools/mvl_lsp_binaries_arm_v5t_le.iso /mnt/cdrom -o loop
or
#mount -t iso9660 /mnt/hgfs/Tools/mvl_cross_binaries_v5t_le.iso /mnt/cdrom -o loop

#mount -t iso9660 /mnt/hgfs/Tools/mvl_devrocket_binaries.iso /mnt/cdrom -o loop

#mount -t iso9660 /mnt/hgfs/Tools/mvl_docs_binaries.iso /mnt/cdrom -o loop
<#/DocByCoryXie#>

Friday, August 17, 2007

SPARC Instruction Types

There are very few addressing modes on the SPARC, and they may be used only in certain very restricted combinations. The three main types of SPARC instructions are given below, along with the valid combinations of addressing modes. There are only a few unusual instructions which do not fall into these catagories.

1. Arithmetic/Logical/Shift instructions

opcode reg1,reg2,reg3    !reg1 op reg2    -> reg3
opcode reg1,const13,reg3 !reg1 op const13 -> reg3
  • All "action" instructions (add, sub, and, or, etc.) take three operands.
  • The destination is always the third operand.
  • The middle operand may be a 13-bit signed constant (-4096...+4095).
  • Otherwise, all operands are registers.
  • Examples:
add %L1,%L2,%L3 !%L1+%L2->%L3
add %L1,1,%L1 !increment L1
sub %g0,%i3,%i3 !negate i3
sub %L1,10,%G0 !compare %L1 to 10 (discard result)
add %L1,%G0,%L2 !move %L1 to %L2 (add 0 to it)
add %G0,%G0,%L4 !clear L4 (0+0 ->%L4)
  • To do the above things in the 680x0, 6 different opcodes would be needed (move, add, addi, clr, neg, cmp)

2. Load/Store Instructions

opcode [reg1+reg2],reg3
opcode [reg1+const13],reg3

  • Only load and store instructions can access memory.
  • The contents of reg3 is read/written from/to the address in memory formed by adding reg1+reg2, or else reg1+const13 (a 13- bit signed constant as above).
  • The operands are written in the reverse direction for store instructions, so that the destination is always last.
  • One of reg1 or const13 can be omitted. The assembler will supply $g0 or 0. (This is a shorthand provided by the assembler. Both are always there in machine language.)
  • Examples:
ld [%L1+%L2],%L3 !word at address [%L1+%L2]->%L3
ld [%L1+8],%L2 !word at address [%L1+8]->%L2
ld [%L1],%L2 !word at address [%L1]->%L2
st %g0,[%i2+0] !0 -> word at address in %i2
st %g0,[%i2] !same as above

3. Branch Instructions

opcode address

  • Branch to (or otherwise use) the address given.
  • There are actually 2 types of addresses (see "relocatability" later) - but they look the same.
  • Examples:
call printf
be Loop

That's it. Period. No other modes or combinations of modes are possible. This is a RISC machine and R stands for "Reduced".

add %L1,[%L2],%L3 !Invalid. No memory access allowed.
ld 5,%L4 !Invalid. Must be a memory access.

SPARC Fundamental Instructions

Load/Store Instructions

  • Only these instructions access memory.
  • All 32 bits of the register are always affected by a load. If a shorter data item is loaded, it is padded by either adding zeroes (for unsigned data), or by sign extension (for signed data).
  • In effect, data in memory may be 1, 2, or 4 bytes long, but data in registers is always 4 bytes long.
ld   - load (load a word into a register)
st - store (store a word into memory)
ldub - load unsigned byte (fetch a byte, pad with 0's)
ldsb - load signed byte (fetch a byte, sign extend it)
lduh - load unsigned halfword (fetch 2 bytes, pad)
ldsh - load signed halfword (fetch 2 bytes, sign extend)
stb - store byte (store only the LSB)
sth - store halfword (store only the 2 LSB's)
  • There are also two instructions for double words. The register number must be even, and 8 bytes are loaded or stored. The MSW goes to the even register and the LSW to the odd register that follows it.
  • ldd - load double (load 2 words into 2 registers)
    std - store double (store 2 words from 2 registers)

    Arithmetic/Logical Instructions

    • All 32 bits of every register is used.
    • Setting the condition code is always optional. Add "cc" to the opcode to set the condition code. By default, it is not set.
    add  - a+b
    sub - a-b
    and - a&b (bitwise AND)
    andn - a&~b (bitwise and - second operand complemented)
    or - a|b (bitwise OR)
    orn - a|~b (bitwise or - second operand complemented)
    xor - a^b (bitwise exclusive or)
    xnor - a^~b (bitwise exor - second operand complemented)
  • Examples:
  • add   %L1,%L2,%L3  ;add %L1+%L2 -> %L3
    subcc %L4,10,%G0 ;sub %L4-10, set cc, discard result
    or %o3,0xFF,%o3 ;set lowest 8 bits of %o3 to 1's
    xnor %L6,%G0,%L6 ;complement %L6 (same as NOT in 680x0)

    Comparison of CISC vs. RISC (680x0 vs. SPARC)

    A RISC (Reduced Instruction Set Computer) achieves the same functionality with a much smaller (and more consistent) instruction set. For example, the sets of instructions below can do roughly the same jobs. (Size modifiers like "ub" after "ld" in SPARC and ".w" after "move" in 680x0 are ignored.)

    680x0:

    add,adda,addi,addq,clr,cmp,cmpa,cmpi,cmpm,exg,
    ext,extb,move,movea,move16,movem,moveq,neg,negx,
    sub,suba,aubi,subq,tst

    SPARC:

    ld,st,addcc,subcc

    How is this reduction made possible?

    • Three operands per instruction
    • The fact that %g0 gives easy access to a 0 value
    • The use of more instructions is expected in some cases. (Example,
      move (a3)+,-(a4)
      in 68000 would require
      ld [%L3],%G1
      add %L3,4,%L3
      sub %L4,4,%L4
      st %G1,[%L4]
      in SPARC.
    • But, in the example above, both machines would likely use about the same number of clock cycles, and the SPARC would have a faster clock because it is simpler, so the SPARC would likely be faster for roughtly equivalent technology.

    CALL Instruction

    This instruction is used to call subprograms. As for the 680x0, we will leave the details for later. For now, it will be used only to call library routines.

    call printf

    SETHI Instruction (and the SET synthetic instruction)

    This instruction is one of the few that has a slightly different assembly-language format. The syntax looks like this:

    sethi const22,%reg

    where "const22" is a 22-bit integer constant (signed or unsigned is not relevant). It places the constant into the high-order 22 bits of the register, and sets the low-order 10 bits of the register to 0's. (?!) For example,

    sethi 0x333333,%L1; 0x333333 is 1100110011001100110011

    would set register %L1 to

    1100110011001100110011 0000000000

    Q: Why would you want to do this? A: In order to load a 32-bit constant (such as an address) into a register. This can't possibly be done in one instruction (since all instructions are 32 bits long, there isn't room for a 32-bit constant and also an opcode and a register number). There are instructions that can set the lower part of a register (add, or, etc), so this one complements those nicely.

    For example, to set %L1 to 0x89ABCDEF, do the following:

    1. Split up 0x89ABCDEF into the top 22 bits and the bottom 10 bits

    89ABCDEF = 10001001101010111100110111101111
    Top 22 bits are 1000100110101011110011 = 226AF3
    Low 10 bits are 0111101111 = 1EF

    2. Place the two halves into %L1 using separate instructions:

    sethi 0x226AF3,%L1
    or %L1,0x1EF,%L1 ;or is better than add. (WHY?)

    Shortcut #1: The SPARC assembler provides two special "functions" to make this easier. %hi(X) will give the top 22 bits of the constant X and %lo(X) will give the bottom 10 bits. This is an assembler feature. It is not part of the SPARC machine language. So we could use

    sethi %hi(0x89ABCDEF),%L1
    or %L1,%lo(0x89ABCDEF),%L1

    The most common use of this instruction is to place the address of something into a register. For example, if there is a character string in memory with the label "Prompt" on it, you can put the address of that string into %o1 using

    sethi %hi(Prompt),%o1
    or %o1,%lo(Prompt),%o1

    Shortcut #2: The above pair of instructions is used quite a lot, so the assembler provides a "synthetic instruction" which will generate them for you. The "instruction"

    set   const32,%reg

    will accept any 32-bit constant (const32) such as an address, and any register (%reg) and will generate

    sethi %hi(const32),%reg
    or %reg,%lo(const32),%reg

    However, it should be remembered that SET is not a real SPARC instruction, and that it produces two machine language instructions, not one.

    NOP Instruction (No OPeration)

    This is another "synthetic instruction". The syntax looks like this:

    nop

    but it really generates the instruction

    sethi 0,%g0

    which does absolutely nothing. All instruction sets have a NOP instruction. In RISC machines, it is often a very essential instruction.

    SPARC Synthetic Instructions

    RISC machine languages do not have many instructions that are common in CISC machine languages (move, negate, clear, compare, etc.) because all of these can be done quite easily with 3-operand add, subtract, and logical instructions. However, the assembler provides "synthetic instructions" to improve convenience and readability. These are not real machine language instructions, but the assembler will automatically translate them into the proper instruction(s) for you.

    In SPARC, some of the most common synthetic instructions are:

    Synthetic Instruction   Assembled As
    --------------------- -----------------------------
    clr %reg or %g0,%g0,%reg
    cmp %reg,%reg subcc %reg,%reg,%g0
    cmp %reg,const subcc %reg,const,%g0
    mov %reg,%reg or %g0,%reg,%reg
    mov const,%reg or %g0,const,%reg

    set const,%reg sethi %hi(const),%reg
    or %reg,%lo(const22),%reg

    And here are some others that may be useful:

    Synthetic Instruction   Assembled As
    --------------------- -----------------------------
    clr [address] st %g0,[address]
    clrh [address] sth %g0,[address]
    clrb [address] stb %g0,[address]
    dec %reg sub %reg,1,%reg
    deccc %reg subcc %reg,1,%reg
    inc %reg add %reg,1,%reg
    inccc %reg addcc %reg,1,%reg
    not %reg xnor %reg,%g0,%reg
    neg %reg sub %g0,%reg,%reg
    tst %reg orcc %reg,%g0,%g0

    Here are two that will be used for subprograms later:

    Synthetic Instruction   Assembled As
    --------------------- -----------------------------
    restore restore %g0,%g0,%g0
    ret jmpl %i7+8,%g0

    Thursday, August 16, 2007

    Reducing Linux Kernel Size

    Here is an article regarding how to reduce code and memory size usage for Linux Kernel.
    http://tree.celinuxforum.org/CelfPubWiki/SystemSizeResources

    Shrinking the kernel with gcc

    Thursday, August 09, 2007

    法国程序员独自完成了235种USB摄像头驱动

    “中国制造”代表便宜,也可能意味着得不到支持。一位60岁的法国医生(medical physicist)Michel Xhaard,热心的linux拥护者,在购买了一个便宜的“中国制造”USB摄像头(webcams)后,发现它没有linux驱动,没有支持网站,甚至制造厂家的地址都没有。于是决定自己动手来写Linux下的驱动,三年之后,他一共完成了数百种“中国制造”的低成本USB摄像头的驱动程序。现在开源操作系统还无法与Windows在易用性上相抗衡,但是有这样热心的人存在我们能够相信有一天是可以实现的。没有资金帮助,或者说即便有金钱也没有多少人能这样坚持下去,他为许多人带来了便利。
    这里是地址:http://mxhaard.free.fr/download.html

    Mixing RVCT 3.1 and GCC 4.1.1

    Hi,

    I am trying to use a RVCT 3.1 compiled library with a GCC 4.1.1 2006q3-26 compiled test application( only C).
    The library has some c files with assembly functions. If I disable those assembly functions using a compile time flag then things link fine without any problems.

    If I enable those assembly functions then library is built without any problems but when I link it with GCC compiled test application then it throws following error
    " Conflicting definitions of wchar_t "

    With RVCT I am using the option "--wchar32" , can it be that the assembler is not using this option ? What might be the problem ?

    Regards,
    Pradeep
    ===========================================================
    Hi ,

    If you check mail archive in the codesourcery you will find answer to this. But I am attaching the link, may be it will solve your problem.

    http://www.codesourcery.com/archives/arm-gnu/msg01314.html

    Even though it is for RVDS 3.0, your problem might be linked...Anyway you can look at APP NOTE 150 on arm's site which will give more insight.

    Cheers,
    Venu

    深入浅出Linux设备驱动之并发控制(转贴)

    在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引发"竞态",因此我们必须对共享资源进行并发控制。Linux内核中解决并发控制的最常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。

      自旋锁与信号量"类似而不类",类似说的是它们功能上的相似性,"不类"指代它们在本质和实现机理上完全不一样,不属于一类。

      自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环查看是否该自旋锁的保持者已经释放了锁,"自旋"就是"在原地打转"。而信号量则引起调用者睡眠,它把进程从运行队列上拖出去,除非获得锁。这就是它们的"不类"。

      但是,无论是信号量,还是自旋锁,在任何时刻,最多只能有一个保持者,即在任何时刻最多只能有一个执行单元获得锁。这就是它们的"类似"。

       鉴于自旋锁与信号量的上述特点,一般而言,自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用;信号量适合于保持时间较长的情况,只能在进程上 下文使用。如果被保护的共享资源只在进程上下文访问,则可以以信号量来保护该共享资源,如果对共享资源的访问时间非常短,自旋锁也是好的选择。但是,如果 被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。

      与信号量相关的API主要有:

      定义信号量

    struct semaphore sem;

      初始化信号量

    void sema_init (struct semaphore *sem, int val);

      该函数初始化信号量,并设置信号量sem的值为val

    void init_MUTEX (struct semaphore *sem);

      该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1,等同于sema_init (struct semaphore *sem, 1);

    void init_MUTEX_LOCKED (struct semaphore *sem);

      该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,等同于sema_init (struct semaphore *sem, 0);

      获得信号量

    void down(struct semaphore * sem);

      该函数用于获得信号量sem,它会导致睡眠,因此不能在中断上下文使用;

    int down_interruptible(struct semaphore * sem);

      该函数功能与down类似,不同之处为,down不能被信号打断,但down_interruptible能被信号打断;

    int down_trylock(struct semaphore * sem);

      该函数尝试获得信号量sem,如果能够立刻获得,它就获得该信号量并返回0,否则,返回非0值。它不会导致调用者睡眠,可以在中断上下文使用。

      释放信号量

    void up(struct semaphore * sem);

      该函数释放信号量sem,唤醒等待者。

      与自旋锁相关的API主要有:

      定义自旋锁

    spinlock_t spin;

      初始化自旋锁

    spin_lock_init(lock)

      该宏用于动态初始化自旋锁lock

      获得自旋锁

    spin_lock(lock)

      该宏用于获得自旋锁lock,如果能够立即获得锁,它就马上返回,否则,它将自旋在那里,直到该自旋锁的保持者释放;

    spin_trylock(lock)

      该宏尝试获得自旋锁lock,如果能立即获得锁,它获得锁并返回真,否则立即返回假,实际上不再"在原地打转";

      释放自旋锁

    spin_unlock(lock)

      该宏释放自旋锁lock,它与spin_trylock或spin_lock配对使用;

    除此之外,还有一组自旋锁使用于中断情况下的API。


    下面进入对并发控制的实战。首先,在globalvar的驱动程序中,我们可以通过信号量来控制对int global_var的并发访问,下面给出源代码:

    #include "linux/module.h"
    #include "linux/init.h"
    #include "linux/fs.h"
    #include "asm/uaccess.h"
    #include "asm/semaphore.h"

    MODULE_LICENSE("GPL");

    #define MAJOR_NUM 254

    static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
    static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);

    struct file_operations globalvar_fops =
    {
      read: globalvar_read,

    write: globalvar_write,
    };
    static int global_var = 0;
    static struct semaphore sem;

    static int __init globalvar_init(void)
    {
     int ret;
     ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
     if (ret)
     {
      printk("globalvar register failure");
     }
     else
     {
      printk("globalvar register success");
      init_MUTEX(&sem);
     }
     return ret;
    }

    static void __exit globalvar_exit(void)
    {
     int ret;
     ret = unregister_chrdev(MAJOR_NUM, "globalvar");
     if (ret)
     {
      printk("globalvar unregister failure");
     }
     else
     {
      printk("globalvar unregister success");
     }
    }

    static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
    {
     //获得信号量
     if (down_interruptible(&sem))
     {
      return - ERESTARTSYS;
     }

     //将global_var从内核空间复制到用户空间
     if (copy_to_user(buf, &global_var, sizeof(int)))
     {
      up(&sem);
      return - EFAULT;
     }

     //释放信号量
     up(&sem);

     return sizeof(int);
    }

    ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
    {
     //获得信号量
     if (down_interruptible(&sem))
     {
      return - ERESTARTSYS;
     }

     //将用户空间的数据复制到内核空间的global_var
     if (copy_from_user(&global_var, buf, sizeof(int)))
     {
      up(&sem);
      return - EFAULT;
     }

     //释放信号量
     up(&sem);
     return sizeof(int);
    }

    module_init(globalvar_init);
    module_exit(globalvar_exit);

       接下来,我们给globalvar的驱动程序增加open()和release()函数,并在其中借助自旋锁来保护对全局变量int globalvar_count(记录打开设备的进程数)的访问来实现设备只能被一个进程打开(必须确保globalvar_count最多只能为1):

    #include "linux/module.h"
    #include "linux/init.h"
    #include "linux/fs.h"
    #include "asm/uaccess.h"
    #include "asm/semaphore.h"

    MODULE_LICENSE("GPL");

    #define MAJOR_NUM 254

    static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
    static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
    static int globalvar_open(struct inode *inode, struct file *filp);
    static int globalvar_release(struct inode *inode, struct file *filp);

    struct file_operations globalvar_fops =
    {
     read : globalvar_read,
    write : globalvar_write,
    open : globalvar_open,
    release: globalvar_release,
    };

    static int global_var = 0;
    static int globalvar_count = 0;
    static struct semaphore sem;
    static spinlock_t spin = SPIN_LOCK_UNLOCKED;

    static int __init globalvar_init(void)
    {
     int ret;
    ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
     if (ret)
     {
      printk("globalvar register failure");
     }
     else
     {
      printk("globalvar register success");
      init_MUTEX(&sem);
     }
     return ret;
    }

    static void __exit globalvar_exit(void)
    {
     int ret;
     ret = unregister_chrdev(MAJOR_NUM, "globalvar");
     if (ret)
     {
      printk("globalvar unregister failure");
     }
     else
     {
      printk("globalvar unregister success");
     }
    }

    static int globalvar_open(struct inode *inode, struct file *filp)
    {
     //获得自选锁
     spin_lock(&spin);

     //临界资源访问
     if (globalvar_count)
     {
      spin_unlock(&spin);
      return - EBUSY;
     }
     globalvar_count++;

     //释放自选锁
     spin_unlock(&spin);
     return 0;
    }

    static int globalvar_release(struct inode *inode, struct file *filp)
    {
     globalvar_count--;
     return 0;
    }

    static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t
    *off)
    {
     if (down_interruptible(&sem))
     {
      return - ERESTARTSYS;
     }
     if (copy_to_user(buf, &global_var, sizeof(int)))
     {
      up(&sem);
      return - EFAULT;
     }
     up(&sem);
     return sizeof(int);
    }

    static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,
    loff_t *off)
    {
     if (down_interruptible(&sem))
     {
      return - ERESTARTSYS;
     }
     if (copy_from_user(&global_var, buf, sizeof(int)))
     {
      up(&sem);
      return - EFAULT;
     }
     up(&sem);
     return sizeof(int);
    }

    module_init(globalvar_init);
    module_exit(globalvar_exit);

      为了上述驱动程序的效果,我们启动两个进程分别打开/dev/globalvar。当一个进程打开/dev/globalvar后,另外一个进程将打开失败,输出"device open failure"。

    使用上一节我附的Makefile进行编译,在开发板上跑没问题,只是没法试验多终端。俺的板子不支持,没办法。今天重读此章,看到两个进程,想到可不可以利用fork函数进行测试。我们试试。
    测试程序如下:
    #include "sys/types.h"

    #include "sys/stat.h"

    #include "stdio.h"

    #include "fcntl.h"

    #include "unistd.h"

    int main(void)
    {

    int fd, num;
    pid_t pid;

    pid=fork();

    if(pid < 0)printf("error in fork!");
    else if (pid == 0)
    {

    printf("I am parent\n");

    fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);

    if (fd != -1 )

    {read(fd, &num, sizeof(int));

    printf("The globalvar is %d\n", num);

    printf("Please input the num \n");

    scanf("%d", &num);

    write(fd, &num, sizeof(int));

    read(fd, &num, sizeof(int));

    printf("The globalvar is %d\n", num);

    close(fd);
    }

    else

    {printf("Device open failure\n");
    }

    }

    else

    {printf( "I am child\n");

    fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);

    if (fd != -1 )

    {read(fd, &num, sizeof(int));

    printf("The globalvar is %d\n", num);

    printf("Please input the num \n");

    scanf("%d", &num);

    write(fd, &num, sizeof(int));

    read(fd, &num, sizeof(int));

    printf("The globalvar is %d\n", num);

    close(fd);
    }

    else

    {printf("Device open failure\n");

    }

    }
    return 0;
    }

    运行结果如下:

    [root@(none)study]$./gtest

    I am parent

    The globalvar is 12

    Please input the num

    I am child

    Device open failure

    [root@(none) study]$

    [root@(none)study]$./gtest

    I am child

    The globalvar is 12

    Please input the num

    I am parent

    Device open failure

    [root@(none)study]$./gtest

    I am child

    The globalvar is 12

    Please input the num

    I am parent

    Device open failure

    呵呵,结果得到了验证。


    Wednesday, August 01, 2007

    XPS Links

    A blog of Feng Yuan focusing on XPS

    A page to track the various projects that make up the Mono-based implementation of Silverlight.