| Ann 的个人资料冥王星人vs火星人的幸福生活照片日志列表 | 帮助 |
|
12月22日 努力推进上海节约型城市建设Via是我认识的人当中,最典型的Dandy了。作为一个男人,从Cleasing,Lotion到Cream甚至mask等等,一个都不少,有时还会用精油。 今天mail时我叫他帮我带Dr. Feel Good回来,他说不一定有,我就急了,然后他居然有脸说我是化妆品狂人。我申辩说自己并没有到狂的程度,至少买回来一半的东西都是用完的。于是他就把他的那套理论说给我听“我也是啊,涂脸的不想用了涂手,涂手的不用了涂身体,涂身体的不想用了就涂脚。” 但我总觉得少了点什么,想了半天才想到:不想涂脚了,也可以拿来涂小宝的呀。不过昨天下午跟小宝电话的时候,我说“我个两天用Dior又发了两粒新额痘痘,个趟回国8侬用算了。”小宝居然说:“嘎摊板额么事侬就8我用了啊?” 无语问苍天啊……上海现在提倡要建设节约型城市,小宝的思想觉悟实在太差了啊!这样以后怎么评五好家庭啊! 12月13日 Ann’s Adventures From Win32 To HP-UX(2)Chapt 2 API函数 ------------- 进程创建 Win32和UNIX差别最大的一个方面就是进程模型。原来Win32系统下用CreateProcess以及CreateThread的函数来创建进程或者线程。到了UNIX下,则调用fork来创建子进程。fork复制的内容包括父进程的数据、堆栈段以及父进程的环境。父进程和子进程以并行的方式执行同一程序的不同分支。至于CreateProcess函数创建了进程后执行另一程序的部分,则可以用exec函数(execl、execle、execlp、execv、execve、execvp)来替代。具体用什么函数,就看需要了。 说到进程的创建,其实我一开始是想要用system来替代CreateProcess,而且man出来有关system的说明,也是调用了fork然后exec的。具体差在哪里,我上网查了一下也没有很详尽的说明,有说system不安全,但是没有给理由;也有说system因为是由shell来实现的,并不是ansi标准函数,如果提供了专门的c函数接口,则应该用fork加exec。关于这一点,我至今有疑问,希望有谁明白的可以解释给我听。 后来看到一篇文章说system有个缺点,就是command line必须严格按照shell的语法进行组织,如果遇到一些特殊字符的话,就比较麻烦。况且我最后要实现的只是单行的command line,所以最后还是用了fork和exec。 另外还有一个函数popen(建立管道I/O),也会调用fork()产生子进程,然后在子进程里调用sh –c来执行command line。但是因为现在项目权限是SUID的,所以没有用这个函数,因为popen会继承环境变量,可能造成系统上的不安全(权限为SGID的程序也要尽量避免使用popen)。
进程等待 Win32有一个函数WaitForSingleObject,可以等待Event;Mutex;Semaphore;Process;Thread。可以看一下它的函数定义: DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); hHandle就是传入的对象句柄,用来判断对象状态。 dwMilliseconds则是传入的Time Out时间,单位ms,可以是范围内用户自定义的任意大小,也可以是INFINITY(值:0x7FFFFFFF,无限制等待)。 此函数返回值如下:
可以通过这个函数来判断创建的子进程所处的状态。虽然也可以通过fork的返回值来判断子进程是否结束,但是原来提供的Win32代码里等待的功能就没有了,我在这里用了poll的函数。 在说poll函数之前,要先说一下pipe函数。 pipe函数,是创建管道函数。函数定义:int pipe(int fdes[2]);pipe函数执行成功后,内核打开两个文件描述字fdes[0],fdes[1],前者为读取端,后者为写入端。如果管道的读取端被关闭后,仍然向写入端写入数据,则进程会收到一个SIGPIPE的信号,表示管道破裂,默认结束进程。 而pipe打开的文件描述字数组,就是poll函数的第一个引数结构体的一个成员变量。poll的函数定义如下: int poll( struct pollfd fds[], nfds_t nfds, int timeout); pollfd构造体定义: struct pollfd { int fd; /* which file descriptor to poll */ short events; /* events we are interested in */ short revents; /* events found on return */ }; nfds是pollfd结构体的个数。 timeout是指定的最大等待时间(单位ms)。(timeout传入-1的时候,则无限制等待,相当于Win32系统下定义的INFINITY)。 poll返回值为-1的时候,相当于原来WaitForSingleObject的WAIT_FAILED;返回值为0的时候,则WAIT_TIMEOUT;其它默认WAIT_OBJECT_0。
进程堆控制 Win32的HeapAlloc函数,用来分配Heap空间,可以先用GetProcessHeap来获取当前进程的heap地址,然后再利用这个函数在这个进程内开辟空间。 关于在Unix下面实现GetProcessHeap函数,我还没有找到方法。这次移植的这一部分机能,原来主要是为了存储GetLogicalDriveStrings函数返回的逻辑驱动器信息,因为Unix没有驱动盘符的概念,所以后来实现GetLogicalDriveStrings函数的功能时,采取了直接判断所在根目录的方法。 查了一些资料,有说可以用标准库函数malloc来作相应的处理。但是有疑问,这个分配出来的空间的话,是不是不在用户进程的堆里面了?希望有高手跟我解释一下。
文件操作 新建文件CreateFile(),这个是Win32里面的API函数。转到HP-UX的平台上,我用了Open函数加上参数O_CREAT来替代。 当然,两个函数并不相同,在MSDN以及man下面都可以查到很完整的解释。下面只列一些比较常用的参数比较:
Open这些参数,定义在usr/include/sys/fcntl.h里面。从这些define值来看,Open函数感觉要比CreateFile要强大很多,比如对于文件内容追加,CreateFile的话,要再调SetFilePointer函数指定参数FILE_END来设定文件指针位置,而Open函数的O_APPEND参数,在打开或者新建文件的同时,就包含了这样一个操作了。 当然关于文件指针的移动,也可以使用lseek(#include <unistd.h>)或者标准库函数fseek.条条大路通罗马,除了看程序需要以外,就是个人喜好问题了。 Win32里面读取文件内容的函数ReadFile(),在HP-UX平台上,我用read函数来代替。虽然标准库函数fread也可以读取文件内容,但是,fread和fopen这些“f系列”的一样,是直接对文件进行操作,而Readfile及read函数的话,则是将内容按照read参数指定的buffer大小来对文件进行操作,从方式上来看read和readfile更为接近。 同样,HP-UX对应WriteFile()的,也就是Write函数了,和read一样,也是根据传入的参数指定字节数,来读取文件内容到buffer。 因为Win32的这些API,都是通过文件句柄来对文件进行操作,所以最后用CloseHandle来关闭这些文件句柄。而UNIX上的这些函数是对文件描述字进行操作,所以最后要用Close来关闭文件描述字。
当然,从Win32到HP-UX移植的话,有很多不同的API,而且,两个系统上同名的库函数可能使用的函数名也不同。例如在编译strnicmp()的时候发生错误提示,然后再去查看string.h的时候没有找到这个函数的定义,查了资料才知道unix下面相同功能的函数是strncasecmp()。 这段时间在网上找了很久,都没有找到系统地将两个系统之间移植的api进行整理的文档,只找到了Win32 API和标准库函数进行比较的日文文档,如果有人需要,可以问我要。
平台移植的话,技术是一个方面,经验也是一个方面。希望乘现在还有三分钟热度,能走多远走多远,虽然只是刚起步,但是龟爬也比停滞不动要来的好吧。
Ann’s Adventures From Win32 To HP-UX(1)Intro ------------ 第一次遇到Win32到HP-UX系统移植的工作,记录一些心得。也算是最近的收获吧,免得小宝说我满脑子都是化妆品。
Chapt 1 数据类型 ------------- Win32顾名思义,当然是32位啦。而这次的代码移植的目标服务器,是HP-UX 11i v2(B.11.23 U ia64),移植代码C语言。 C语言的数据类型在32位环境下用的是ILP32的数据类型,而64位Unix平台下,使用的是LP64的数据类型。在移植的过程中,char、int、short、long long等都没有发生长度的改变。而long和point型,则由32位变成了64位。因此,原先在ILP32下转换正常的代码,现在在LP64的环境下,就有可能发生意料之外的数据截断,导致程序错误。例如下面这段代码: //--------------------------------- long lvar; scanf(“%d”,&lvar); //---------------------------------- 这样的话,lvar取得32位的值之后,后面的4个字节就被截断了。转换截断的错误通常都比较隐秘,一开始就警惕的话,可以避免浪费很多寻找问题所在的时间。下表列出以上所说的数据模型对比,另外再附上windows 64使用的LLP64数据模型以供参考。
我在论坛上看到一位仁兄说的关于32位HP-UX到64位Linux转换有关数据类型长度问题的总结,从Win32到64位Unix的话,也大致如此,所以在这里引用一下:
a ) int func(); b ) return val; c ) void func( int val ); d ) (const void*)&val.. e ) struct stat st; a) 和 b) : 在函数的定义返回值时要注意此返回值是否会作复值或者类型转换,如果返回值不当会引起数据截断。 c) : 函数的参数定义时,要注意在函数外部传递参数和在内部使用参数时会不会有类型转换之类的引起错误的地方。 d) : 在强制转换一个数据类型时要注意转换前和转换后的数据长度是否一致,64位强制转换成32位或者反过来都会引起程序错误。 e) : 在一些系统的结构体中的一些成员,在64位平台上其长度已经发生变化,不能对其向32位那样的处理,在使用这些结构体时要注意。 最后再补充一点,就是原先那些以十六进制和二进制定义的常量,在64位系统中,可能会发生改变。例如0xFFFFFFFF,在64位系统中这个值不是-1,而是4294967295,正确的值则应该是0xFFFFFFFFFFFFFFFF。所以声明这类常量时,可以使用const signed或const unsigned。
|
|
|