|
在前面,我們接觸到了很多函數(shù)能夠?qū)崿F(xiàn)系統(tǒng)相關(guān)的功能,比如解析命令行參數(shù)、控制進程以及映射內(nèi)存等等。實際上,這些函數(shù)能夠分為兩大類: Linux提供了200多種不同的系統(tǒng)調(diào)用。他們大多聲明在/usr/include/asm/unistd.h文件里。 1 strace命令strace命令能夠跟蹤另一個程序的執(zhí)行情況,給出其執(zhí)行的系統(tǒng)調(diào)用和接收到的信號中斷。
如果要追蹤hostname命令,就可以執(zhí)行: $ strace hostnameexecve('/bin/hostname', ['hostname'], [/* 10 vars */]) = 0brk(0) = 0x255f000access('/etc/ld.so.nohwcap', F_OK) = -1 ENOENT (No such file or directory)mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3f38000access('/etc/ld.so.preload', R_OK) = -1 ENOENT (No such file or directory)open('/etc/ld.so.cache', O_RDONLY|O_CLOEXEC) = 3fstat(3, {st_mode=S_IFREG|0644, st_size=16300, ...}) = 0mmap(NULL, 16300, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe7b3f34000close(3) = 0access('/etc/ld.so.nohwcap', F_OK) = -1 ENOENT (No such file or directory)open('/lib/x86_64-linux-gnu/libnsl.so.1', O_RDONLY|O_CLOEXEC) = 3read(3, '\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`A\0\0\0\0\0\0'..., 832) = 832fstat(3, {st_mode=S_IFREG|0644, st_size=97296, ...}) = 0mmap(NULL, 2202328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe7b3afe000mprotect(0x7fe7b3b15000, 2093056, PROT_NONE) = 0mmap(0x7fe7b3d14000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7fe7b3d14000mmap(0x7fe7b3d16000, 6872, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3d16000close(3) = 0access('/etc/ld.so.nohwcap', F_OK) = -1 ENOENT (No such file or directory)open('/lib/x86_64-linux-gnu/libc.so.6', O_RDONLY|O_CLOEXEC) = 3read(3, '\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0'..., 832) = 832fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe7b3739000mprotect(0x7fe7b38f4000, 2093056, PROT_NONE) = 0mmap(0x7fe7b3af3000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7fe7b3af3000mmap(0x7fe7b3af9000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3af9000close(3) = 0mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3f33000mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3f31000arch_prctl(ARCH_SET_FS, 0x7fe7b3f31740) = 0mprotect(0x7fe7b3af3000, 16384, PROT_READ) = 0mprotect(0x7fe7b3d14000, 4096, PROT_READ) = 0mprotect(0x602000, 4096, PROT_READ) = 0mprotect(0x7fe7b3f3a000, 4096, PROT_READ) = 0munmap(0x7fe7b3f34000, 16300) = 0brk(0) = 0x255f000brk(0x2580000) = 0x2580000uname({sys='Linux', node='391e4e96744b', ...}) = 0fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), ...}) = 0mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe7b3f37000write(1, '391e4e96744b\n', 13391e4e96744b) = 13exit_group(0) = ?+++ exited with 0 +++
隨后的輸出結(jié)果中每一行都代表一個系統(tǒng)調(diào)用——系統(tǒng)調(diào)用名稱、參數(shù)以及返回值。strace命令只能顯示系統(tǒng)調(diào)用,不能顯示普通函數(shù)。 strace命令有助于記錄程序的運行過程。
2 access-測試文件權(quán)限access可以檢查調(diào)用進程是否有文件的讀寫或執(zhí)行權(quán)限,也可以用來檢查文件是否存在。
access接收兩個參數(shù):文件路徑;測試權(quán)限:R_OK、W_OK、X_OK分別對應(yīng)于讀、寫、執(zhí)行等權(quán)限。如果測試權(quán)限全部通過,調(diào)用返回0;如果文件存在,但是權(quán)限測試沒有通過,就會返回-1,并將ERRNO設(shè)置為EACCES(或者EROFS,如果是在一個只讀文件上測試寫權(quán)限)。
如果第二個參數(shù)設(shè)置為F_OK,調(diào)用就只會測試文件是否存在。如果文件存在,返回0;不過不存在,返回-1,并將ERRNO設(shè)置為ENOENT。如果文件路徑中的某一級目錄都無法訪問,那么ERRNO也會被設(shè)置為EACCES。 #include #include #include int main (int argc, char* argv[]) { char* path = argv[1]; int rval; /* Check file existence. */ rval = access (path, F_OK); if (rval == 0) printf (“%s exists\n”, path); else { if (errno == ENOENT) printf (“%s does not exist\n”, path); else if (errno == EACCES) printf (“%s is not accessible\n”, path); return 0; } /* Check read access. */ rval = access (path, R_OK); if (rval == 0) printf (“%s is readable\n”, path); else printf (“%s is not readable (access denied)\n”, path); /* Check write access. */ rval = access (path, W_OK); if (rval == 0) printf (“%s is writable\n”, path); else if (errno == EACCES) printf (“%s is not writable (access denied)\n”, path); else if (errno == EROFS) printf (“%s is not writable (read-only filesystem)\n”, path); return 0;}
3 fcntlfcntl調(diào)用能夠?qū)Υ蜷_的文件描述符執(zhí)行高級操作。第一個參數(shù)是文件描述符;第二個參數(shù)指明了執(zhí)行哪一種操作。這里解釋一下鎖定文件的操作。其他用途可以查看man手冊。
fcntl調(diào)用加鎖類似于多進程中的互斥鎖??梢杂卸鄠€擁有讀取鎖的進程同時讀取文件,但所有擁有寫入鎖的進程中,只能同時有一個進程寫入文件。需要注意的是,沒有調(diào)用fcntl的進程可以無限制讀寫文件。也就是,fcntl調(diào)用的加鎖只適用于同樣調(diào)用fcntl的進程。
要鎖定文件,得先新建一個flock結(jié)構(gòu)變量。將其中的l_type域設(shè)定為F_RDLCK或F_WRLCK,分別對應(yīng)于讀取鎖、寫入鎖。然后調(diào)用fcntl,傳入文件描述符、F_SETLCKW操作符以及前面結(jié)構(gòu)體的指針。如果已經(jīng)有進程持有鎖,那么新的fcntl調(diào)用就會保持阻塞直到前一個鎖被釋放。 下面代碼可以將命令行里的文件加上寫入鎖,然后等待用戶按下ENTER鍵,再執(zhí)行解鎖并關(guān)閉文件。 #include #include #include #include int main (int argc, char* argv[]) { char* file = argv[1]; int fd; struct flock lock; printf (“opening %s\n”, file); /* Open a file descriptor to the file. */ fd = open (file, O_WRONLY); printf (“l(fā)ocking\n”); /* Initialize the flock structure. */ memset (&lock, 0, sizeof(lock)); lock.l_type = F_WRLCK; /* Place a write lock on the file. */ fcntl (fd, F_SETLKW, &lock); printf (“l(fā)ocked; hit Enter to unlock... “); /* Wait for the user to hit Enter. */ getchar (); printf (“unlocking\n”); /* Release the lock. */ lock.l_type = F_UNLCK; fcntl (fd, F_SETLKW, &lock); close (fd); return 0;}
如果想讓fcntl執(zhí)行非阻塞加鎖操作,可以把F_SETLKW替換為F_SETLK。如果無法加鎖,就會立即返回-1。 Linux里flock也可以執(zhí)行相似的文件加解鎖操作,但是fcntl的優(yōu)勢是可以在NFS文件系統(tǒng)中使用。 4 fsync和fdatasync——沖刷磁盤緩存Linux系統(tǒng)通常會將進程的寫磁盤操作暫存在磁盤緩存上,等到緩存滿了或者其他條件滿足時,將所有內(nèi)容一并寫入。但是如果,系統(tǒng)突然崩潰或者系統(tǒng)電源失效,緩存中的內(nèi)容會立刻消失無法挽回。所以,有些重要內(nèi)容需要立即寫入磁盤,而不是留在緩存。 Linux的fsync調(diào)用可以將文件立刻寫入磁盤。該調(diào)用只需要一個參數(shù)——文件描述符。fsync會一直阻塞直到所有數(shù)據(jù)寫入磁盤。 #include #include #include #include #include const char* journal_filename = “journal.log”;void write_journal_entry (char* entry) { int fd = open (journal_filename, O_WRONLY | O_CREAT | O_APPEND, 0660); write (fd, entry, strlen (entry)); write (fd, “\n”, 1); fsync (fd); close (fd);}
fdatasync也可以實現(xiàn)類似功能。不像前者,fdatasync無法保證更新文件的“修改時間”,但是運行速度更快。
利用fsync可以實現(xiàn)同步I/O,保證所有寫入按順序立刻執(zhí)行。這一文件必須用open打開,并傳入O_SYNC選項。 5 getrlimit和setrlimit——限制資源Linux里有一個ulimit命令可以限制程序?qū)ο到y(tǒng)資源的獲取。Linux還提供了getrlimit和setrlimit兩個系統(tǒng)調(diào)用可以實現(xiàn)類似的功能。 每類資源有兩種限制——硬性限制和軟性限制。軟性限制不會超過硬性限制。只有Root用戶可以改變硬性限制。 getrlimit和setrlimit調(diào)用的第一個參數(shù)都是要限制的資源類型;第二個參數(shù)是一個rlimit結(jié)構(gòu)體變量指針。rlimit結(jié)構(gòu)體有兩個域:rlim_cur是軟性限制,rlim_max是硬性限制。
對于第一個參數(shù),最常限制的資源有: RLIMIT_CPU,程序使用的最大CPU時間,單位為秒。程序如果運行超時,就會被SIGXCPU信號中止;RLIMIT_DATA,程序的最大內(nèi)存占用。超出限制的申請都會被系統(tǒng)否決。RLIMIT_NPROC,程序的最多子進程數(shù)量。超出限制的fork調(diào)用都會失敗。RLIMIT_NOFILE,程序的最多同時打開的文件描述符數(shù)量。- 更多內(nèi)容可以查看
setrlimit的man手冊頁。
示例,設(shè)置CPU限制。 #include #include #include int main () { struct rlimit rl; /* Obtain the current limits. */ getrlimit (RLIMIT_CPU, &rl); /* Set a CPU limit of 1 second. */ rl.rlim_cur = 1; setrlimit (RLIMIT_CPU, &rl); /* Do busy work. */ while (1); return 0;}
6 getrusage——進程統(tǒng)計getrusage可以從內(nèi)核獲取進程的運行情況統(tǒng)計。第一個參數(shù):如果是RUSAGE_SELF,就只統(tǒng)計進程本身;如果是RUSAGE_CHILDREN,就會統(tǒng)計進程所衍生出的所有子進程。第二個參數(shù)是一個rusage結(jié)構(gòu)體變量指針,用來放置結(jié)果。
rusage結(jié)構(gòu)體含有三個域:
ru_utime——一個timeval結(jié)構(gòu)體,表示進程執(zhí)行用戶程序的時間,單位為秒。ru_stime——一個timeval結(jié)構(gòu)體,表示進程執(zhí)行系統(tǒng)調(diào)用的時間,單位為秒。ru_maxrss——進程在執(zhí)行過程中,一度擁有的最大物理內(nèi)存。
#include #include #include #include void print_cpu_time() { struct rusage usage; getrusage (RUSAGE_SELF, &usage); printf (“CPU time: %ld.%06ld sec user, %ld.%06ld sec system\n”, usage.ru_utime.tv_sec, usage.ru_utime.tv_usec, usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);}
7 gettimeofday——系統(tǒng)時鐘gettimeofday調(diào)用可以直接讀取系統(tǒng)時鐘。調(diào)用時需要傳入一個timeval類型結(jié)構(gòu)體變量指針。這一結(jié)構(gòu)體可以保存系統(tǒng)時鐘,單位為秒。timeval類型結(jié)構(gòu)體有兩個域:tv_sec域里面是秒數(shù),tv_usec域里面是毫秒數(shù)。timeval類型結(jié)構(gòu)體里的數(shù)字是指從1970年1月1日UTC 0:00起算的累加時間。該調(diào)用在中聲明。
timeval類型結(jié)構(gòu)體中的數(shù)據(jù)并不直觀??梢允褂?code>localtime和strftime庫函數(shù)來做進一步處理。localtime可以把timeval結(jié)構(gòu)體的tv_sec域處理為tm結(jié)構(gòu)體。而strftime可以把tm結(jié)構(gòu)體中的數(shù)據(jù)輸出為格式化的字符串。
#include #include #include #include void print_time () { struct timeval tv; struct tm* ptm; char time_string[40]; long milliseconds; /* Obtain the time of day, and convert it to a tm struct. */ gettimeofday (&tv, NULL); ptm = localtime (&tv.tv_sec); /* Format the date and time, down to a single second. */ strftime (time_string, sizeof (time_string), “%Y-%m-%d %H:%M:%S”, ptm); /* Compute milliseconds from microseconds. */ milliseconds = tv.tv_usec / 1000; /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */ printf (“%s.%03ld\n”, time_string, milliseconds);}
8 mlock系列調(diào)用——鎖定物理內(nèi)存mlock系列調(diào)用可以使程序鎖定其部分或全部地址空間所對應(yīng)的物理內(nèi)存。這樣,即使程序有一段時間沒有訪問這些頁面,系統(tǒng)也不會把他們調(diào)換出去。
這一功能對于一些難以預(yù)測內(nèi)存使用的程序很有用。另外,還有一些對安全有很高要求的程序,需要避免某些數(shù)據(jù)在系統(tǒng)調(diào)換頁面時被寫入磁盤。因為這些寫入磁盤的數(shù)據(jù)有可能在程序結(jié)束后被別有用心的從磁盤文件中恢復(fù)。 鎖定內(nèi)存很簡單,向mlock傳入內(nèi)存起始地址和內(nèi)存總長即可。下例展示了如何鎖定32MB內(nèi)存空間。 const int alloc_size = 32 * 1024 * 1024; char* memory = malloc (alloc_size); mlock (memory, alloc_size);
上述操作并不保證系統(tǒng)為調(diào)用進程單獨保留頁面,因為系統(tǒng)會執(zhí)行“寫時復(fù)制”策略。為了保證調(diào)用進程能有獨享的內(nèi)存空間,可以執(zhí)行下列代碼: size_t i;size_t page_size = getpagesize ();for (i = 0; i < alloc_size; i += page_size) memory[i] = 0;
調(diào)用munlock來解鎖物理內(nèi)存。 調(diào)用mlockall一次性鎖定太多內(nèi)存會非常危險。因為,其他進程就只能有少量內(nèi)存資源。為了保證正常運行,系統(tǒng)不得不頻繁的調(diào)換頁面。嚴(yán)重時,會導(dǎo)致內(nèi)存抖動(thrashing),從而大幅降低系統(tǒng)性能。隨意最好漸進地鎖定物理內(nèi)存。 因此,調(diào)用mlock、mlockall的權(quán)限被限制在root用戶手里。非root進程試圖調(diào)用mlock族函數(shù)時,會出錯,調(diào)用返回-1,并將ERRNO設(shè)置為EPERM。 munlockall可以把所有被鎖定的物理內(nèi)存都釋放掉。
使用top命令可以查看進程的內(nèi)存使用情況。SIZE欄里是進程的虛擬內(nèi)存頁面大??;RSS欄里是進程駐留在物理內(nèi)存的大小。 mlock系列調(diào)用聲明在文件中。
9 mprotect——設(shè)置內(nèi)存權(quán)限前面介紹了mmap調(diào)用,可以將文件映射到內(nèi)存中。mmap調(diào)用第三個參數(shù)可以將頁面權(quán)限設(shè)置為PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE,分別對應(yīng)于“讀”,“寫”,“執(zhí)行”以及“禁止”。 當(dāng)內(nèi)存被聲明之后,可以使用mprotect調(diào)用來修改內(nèi)存權(quán)限,傳入?yún)?shù):內(nèi)存地址、內(nèi)存長度以及一組保護位參數(shù)。需要注意的是,內(nèi)存地址必須與頁面大小對齊,內(nèi)存長度必須是頁面大小的整數(shù)倍。 獲取對齊的頁面 通常,malloc獲取的內(nèi)存地址是沒有對齊的,即使長度是頁面大小的整數(shù)倍。所以要使用mprotect來修改內(nèi)存權(quán)限,必須聲明一個超過需求的內(nèi)存區(qū)域。
使用方法演示。 # Map file to memoryint fd = open (“/dev/zero”, O_RDONLY);char* memory = mmap (NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);close (fd);# change the access methodmprotect (memory, page_size, PROT_READ);
完整示例。 #include #include #include #include #include #include #include #include static int alloc_size; static char* memory;void segv_handler (int signal_number) { printf (“memory accessed!\n”); mprotect (memory, alloc_size, PROT_READ | PROT_WRITE); }int main () { int fd; struct sigaction sa; /* Install segv_handler as the handler for SIGSEGV. */ memset (&sa, 0, sizeof (sa)); sa.sa_handler = &segv_handler; sigaction (SIGSEGV, &sa, NULL); /* Allocate one page of memory by mapping /dev/zero. Map the memory as write-only, initially. */ alloc_size = getpagesize (); fd = open (“/dev/zero”, O_RDONLY); memory = mmap (NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0); close (fd); /* Write to the page to obtain a private copy. */ memory[0] = 0; /* Make the memory unwritable. */ mprotect (memory, alloc_size, PROT_NONE); /* Write to the allocated memory region. */ memory[0] = 1; /* All done; unmap the memory. */ printf (“all done\n”); munmap (memory, alloc_size); return 0;}
10 nanosleep——高精度休眠調(diào)用nanosleep是UNIX系統(tǒng)的休眠指令sleep調(diào)用的高精度版本。
nanosleep的參數(shù)是一個timespec結(jié)構(gòu)體指針。其計時精度能夠達到10毫秒級別。這一特性能夠幫助程序調(diào)度平凡執(zhí)行的短時任務(wù)。timespec結(jié)構(gòu)體有兩個域:tv_sec里面是整數(shù)秒時,tv_nsec是其余的毫秒數(shù)。tv_nsec的數(shù)值不能超過109。
nanosleep的另一個特點是容易恢復(fù)。如果系統(tǒng)在運行sleep或nanosleep時,收到信號中斷,調(diào)用會立刻返回-1,并將ERRON設(shè)置為EINTR。如果是nanosleep的第二個參數(shù)——一個timespec結(jié)構(gòu)體指針非NULL,那么nanosleep調(diào)用會在這個結(jié)構(gòu)體里存儲剩余時間。當(dāng)nanosleep返回后,系統(tǒng)可以借助這個結(jié)構(gòu)體做進一步判斷。
#include #include int better_sleep (double sleep_time) { struct timespec tv; /* Construct the timespec from the number of whole seconds... */ tv.tv_sec = (time_t) sleep_time; /* ... and the remainder in nanoseconds. */ tv.tv_nsec = (long) ((sleep_time - tv.tv_sec) * 1e+9); while (1) { /* Sleep for the time specified in tv. * If interrupted by a signal, * place the remaining time left to sleep back into tv. */ int rval = nanosleep (&tv, &tv); if (rval == 0) /* Completed the entire sleep time; all done. */ return 0; else if (errno == EINTR) /* Interrupted by a signal. Try again. */ continue; else /* Some other error; bail out. */ return rval; } return 0;}
11 readlink——讀取符號鏈接readlink能夠讀取符號鏈接所指向的本源。需要傳入三個參數(shù):符號鏈接的路徑,用于追溯本源的緩存以及緩存長度。
Unusually, readlink does not NUL-terminate the target path that it fills into the buffer. It does, however, return the number of characters in the target path, so NUL-terminating the string is simple.
如果第一個參數(shù)并非符號鏈接,調(diào)用就會返回-1,并將ERRNO設(shè)置為EINVL。 #include #include #include int main (int argc, char* argv[]) { char target_path[256]; char* link_path = argv[1]; /* Attempt to read the target of the symbolic link. */ int len = readlink (link_path, target_path, sizeof (target_path)); if (len == -1) { /* The call failed. */ if (errno == EINVAL) /* It’s not a symbolic link; report that. */ fprintf (stderr, “%s is not a symbolic link\n”, link_path); else /* Some other problem occurred; print the generic message. */ perror (“readlink”); return 1; } else { /* NUL-terminate the target path. */ target_path[len] = ‘\0’; /* Print it. */ printf (“%s\n”, target_path); return 0; }}
12 sendfile——文件快速發(fā)送器sendfile可以將一個文件描述符里的內(nèi)容拷貝到另一個文件描述符里。這個描述符對應(yīng)的可以是磁盤文件,也可以是套接字或者設(shè)備文件。
通常的文件拷貝方式是先將文件內(nèi)容拷貝到內(nèi)存的緩存區(qū)中,然后從緩存區(qū)拷貝到磁盤中。這個方法效率偏低,中途需要額外的內(nèi)存區(qū)域,還需要兩次拷貝過程。 使用sendfile方法可以省去中間的緩存要求。需要傳入,讀寫文件兩個描述符,一個讀取偏離量,一個需要傳送的字節(jié)長度。讀取偏離量是指讀取文件從文件開始(0)算起應(yīng)該開始讀取的位置。 sendfile調(diào)用聲明在中。
#include #include #include #include #include #include #include int main (int argc, char* argv[]) { int read_fd; int write_fd; struct stat stat_buf; off_t offset = 0; /* Open the input file. */ read_fd = open (argv[1], O_RDONLY); /* Stat the input file to obtain its size. */ fstat (read_fd, &stat_buf); /* Open the output file for writing, * with the same permissions as the source file. */ write_fd = open (argv[2], O_WRONLY | O_CREAT, stat_buf.st_mode); /* Blast the bytes from one file to the other. */ sendfile (write_fd, read_fd, &offset, stat_buf.st_size); /* Close up. */ close (read_fd); close (write_fd); return 0;}
13 setitimer——設(shè)置間隔時間setitimer可以幫助進程在未來一個固定時間后發(fā)送一個信號。
有三種計時器: ITIMER_REAL,進程在固定時間后發(fā)送一個SIGALARM信號。這個時間段根據(jù)系統(tǒng)時鐘計算。ITIMER_VIRTUAL,進程在固定時間后發(fā)送一個SIGVTALARM信號。如果在這之間,進程暫停的時間(哪怕是進程陷入內(nèi)核的時間也不算)不計入其中。ITIMER_PROF,進程在固定時間后發(fā)送一個SIGPROF信號。進程運行的時間或者進程陷入內(nèi)核的時間都計入其中。
setitimer的第一個參數(shù)就是上述計時器類型;第二個參數(shù)是一個itimerval結(jié)構(gòu)體指針;第三個參數(shù)如果不是NULL,那可以放入另一個計時器的itimerval結(jié)構(gòu)體指針。
itimerval結(jié)構(gòu)體有兩個域:it_value是一個timeval結(jié)構(gòu)體,里面包含了計時器失效時間,如果為0,則計時器無效;it_interval也是一個timeval結(jié)構(gòu)體,決定了計時器超時之后的行為:如果為0;計時器超時之后立刻失效,如果為一個非零正數(shù),計時器超時之后會以新的時間循環(huán)計時。
#include #include #include #include void timer_handler (int signum) { static int count = 0; printf (“timer expired %d times\n”, ++count); }int main () { struct sigaction sa; struct itimerval timer; /* Install timer_handler as the signal handler for SIGVTALRM. */ memset (&sa, 0, sizeof (sa)); sa.sa_handler = &timer_handler; sigaction (SIGVTALRM, &sa, NULL); /* Configure the timer to expire after 250 msec... */ timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 250000; /* ... and every 250 msec after that. */ timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 250000; /* Start a virtual timer. It counts down whenever this process is executing. */ setitimer (ITIMER_VIRTUAL, &timer, NULL); /* Do busy work. */ while (1); /* * NO RETURN ?? */}
14 sysinfo——獲取系統(tǒng)統(tǒng)計信息sysinfo能夠?qū)⑾到y(tǒng)信息寫入sysinfo結(jié)構(gòu)體。該結(jié)構(gòu)體有四個域:
uptime——自系統(tǒng)啟動之后過去的時間,單位為秒totalram——可用物理內(nèi)存的總計freeram——沒有使用的物理內(nèi)存procs——系統(tǒng)進程數(shù)量
sysinfo結(jié)構(gòu)體詳情可查Linux手冊sysinfo頁。
要使用sysinfo調(diào)用,必須引入,和三個文件。 #include #include #include #include int main (){ /* Conversion constants. */ const long minute = 60; const long hour = minute * 60; const long day = hour * 24; const double megabyte = 1024 * 1024; /* Obtain system statistics. */ struct sysinfo si; sysinfo (&si); /* Summarize interesting values. */ printf (“system uptime : %ld days, %ld:%02ld:%02ld\n”, si.uptime / day, (si.uptime % day) / hour, (si.uptime % hour) / minute, si.uptime % minute); printf (“total RAM : %5.1f MB\n”, si.totalram / megabyte); printf (“free RAM : %5.1f MB\n”, si.freeram / megabyte); printf (“process count : %d\n”, si.procs); return 0;}
15 unameuname調(diào)用可以將系統(tǒng)信息填入utsname結(jié)構(gòu)體中。uname調(diào)用定義在中。
utsname結(jié)構(gòu)體中有六個域:
sysname——系統(tǒng)名稱,比如Linuxrelease version——系統(tǒng)的發(fā)行號和版本級別machine——硬件平臺信息,對于x86 Linux,這里就是i386或i686node——系統(tǒng)主機名__domain——系統(tǒng)域名
#include #include int main () { struct utsname u; uname (&u); printf (“%s release %s (version %s) on %s\n”, u.sysname, u.release, u.version, u.machine); return 0;}
|