顯示具有 Linux 應用程式篇 標籤的文章。 顯示所有文章
顯示具有 Linux 應用程式篇 標籤的文章。 顯示所有文章

星期六, 5月 19, 2007

建構 Insight 6.1

V1.2

copyright@2006

email: mesmerli@hotmail.com

什麼是 Insight?

本文主要介紹如何建構搭配 ARM 處理器的應用程式除錯工具。

Insight 是一個可以搭配 gdbserver 的圖形化除錯工具。

建構 Insight 6.1

解壓縮 insight 6.1 所有原始碼到一個檔案夾,

接下來,在該檔案夾下建立以下檔案夾

  1. insight-arm-linux-6.1
  2. gdbserver-arm-6.1.

完畢後,檔案夾結構應如下所示:

  1. ./gdbserver-arm-6.1 (empty)
  2. ./insight-6.1 (the source tree)
  3. ./insight-arm-linux-6.1 (empty)
進入 insight-arm-linux-6.1 檔案夾下使用下面的命令建構 Insight 主程式

# cd /usr/src/creator/nfs/Day1/insight-6.1/insight-arm-linux-6.1
# ../insight-6.1/configure --host=i686-pc-linux --target=arm-linux --prefix=/usr/local/insight-arm-6.1 --enable-sim

# make
# make install


接下來,進入 gdbserver-arm-6.1 檔案夾建構 gdbserver

ARM 版本須進行以下修改:

修改 linux-arm-low.c

1. vi ../insight-6.1/gdb/gdbserver/linux-arm-low.c

2. remark #include <sys/reg.h> in line 26

# ../insight-6.1/gdb/gdbserver/configure --target=arm-linux

Note:

修改 Make File

1. vi Makefile

2. change gcc to arm-linux-gcc in line 52

# make

使用Insight 與 gdbserver 除錯

  1. 在 gdbserver-arm-6.1 目錄夾找到 "gdbserver",並把它放到您的實驗板檔案系統中。
  2. 重新編譯您的應用程式,並且使用 -ggdb 選項重新編譯。
  3. 啟動您的實驗板,並使用以下的命令在實驗板執行應用程式
    # gbdserver <your PC TCP/IP address>:<2345 or your port> <your program> <your arguments>
  4. 在 Host 端執行 Insight。 /usr/local/insight-arm-6.1/bin/arm-linux-insight
  5. 在 Insight 圖形介面,依下面說明操作

在 "File" -> "Target settings" 選單設定以下選項

Connection:
Target: GDBserver/TCP
Hostname:
Port: 2345 (or any free port you want)

展開 "More options",
Run Options:
[x] Attach to Target
[ ] Download program

Run Method:
< > Run program
<x>Continue from last stop

在 global options 中,確認 "Set breakpoint at main" 被選取。

  1. 在 Insight選單中選擇"run"->"Run",並選擇 ARM program binary。
  2. gdbserver 此時應已與 Insight 連線,所以此時可使用 Insight 除錯實驗板上的應用程式。

後記

  1. gdbserver只適合除錯應用程式,無法除錯 Linux 核心或核心模組 (Kernel Module)。
  2. 如不想使用圖形化介面,亦可使用 GDB 文字模式除錯。

星期四, 5月 17, 2007

Process API

V1.0

copyright@2006

email: mesmerli@hotmail.com

前言

本文主要說明 Linux 下,與 Process 相關的API。



system1 執行一個外部程式,並等待外部程式執行完畢後,才繼續執行主程式。

Note: 由 "Done." 的輸出位置可以判斷主程式是否等待外部程式

system1.c

#include <stdlib.h>
#include <stdio.h>

int main()
{
printf("Running ps with systemn");
system("ps -ax");
printf("Done.n");
exit(0);
}


System2 同樣執行一個外部程式,但放到背景執行。所以主程式在外部程式上為執行完畢前,便印出 "Done."

system2.c

#include <stdlib.h>
#include <stdio.h>

int main()
{
printf("Running ps with systemn");
system("ps -ax &");
printf("Done.n");
exit(0);
}


pexec 所執行的外部程式,取代主程式,所以 "Done." 不會被印出

pexec.c

#include <unistd.h>
#include <stdio.h>

int main()
{
printf("Running ps with execlpn");
execlp("ps", "ps", "-ax", 0);
printf("Done.n");
exit(0);
}



fork1 使用 fork 函數建立兩個程序,fork 函數會給兩個程序不同的 Return value

父程序得到子程序的 Process ID, 子程序得到 0

fork1.c

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
pid_t pid;
char *message;
int n;

printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 5;
break;
default:
message = "This is the parent";
n = 3;
break;
}

for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}



使用 wait 函數有以下功能

1. 暫停執行直到子程序結束

2. 取得子程序的返回值

3. 讓作業系統回收子程序所佔用的資源,否成會變成 Zombie Process

wait.c

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
pid_t pid;
char *message;
int n;
int exit_code;

printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
exit(1);
case 0:
message = "This is the child";
n = 5;
exit_code = 37;
break;
default:
message = "This is the parent";
n = 3;
exit_code = 0;
break;
}

for(; n > 0; n--) {
puts(message);
sleep(1);
}

/* This section of the program waits for the child process to finish. */

if(pid) {
int stat_val;
pid_t child_pid;

child_pid = wait(&stat_val);

printf("Child has finished: PID = %dn", child_pid);
if(WIFEXITED(stat_val))
printf("Child exited with code %dn", WEXITSTATUS(stat_val));
else
printf("Child terminated abnormallyn");
}
exit (exit_code);
}



fork2 試著在父程序結束前,讓子程序變成 zombie process

Note: 在副程序結束前,可使用 "ps -al" 觀察

fork2.c

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
pid_t pid;
char *message;
int n;

printf("fork program startingn");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 3;
break;
default:
message = "This is the parent";
n = 5;
break;
}

for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}


使用 toupper 函數將小寫變大寫,供 useupper 作為外部程式

upper.c

#include <stdio.h>
#include <ctype.h>

int main()
{
int ch;
while((ch = getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}


利用 freopen 函數轉向 stdin 變成檔案輸入

useupper.c

/* This code, useupper.c, accepts a file name as an argument
and will respond with an error if called incorrectly. */

#include <unistd.h>
#include <stdio.h>

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

if(argc != 2) {
fprintf(stderr, "usage: useupper filen");
exit(1);
}

filename = argv[1];

/* That done, we reopen the standard input, again checking for any errors as we do so,
and then use execl to call upper. */

if(!freopen(filename, "r", stdin)) {
fprintf(stderr, "could not redirect stdin to file %sn", filename);
exit(2);
}

execl("./upper", "upper", 0);

/* Don't forget that execl replaces the current process;
provided there is no error, the remaining lines are not executed. */

fprintf(stderr, "could not exec upper!n");
exit(3);
}


使用 signal 函數註冊 signal handler

本範例可以讓 signal handler 讓 Ctrl+C 原本中斷功能失效

ctrlc1.c

/* We'll start by writing the function which reacts to the signal
which is passed in the parameter sig.
This is the function we will arrange to be called when a signal occurs.
We print a message, then reset the signal handling for SIGINT
(by default generated by pressing CTRL-C) back to the default behavior.
Let's call this function ouch. */

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
printf("OUCH! - I got signal %dn", sig);
(void) signal(SIGINT, SIG_DFL);
}

/* The main function has to intercept the SIGINT signal generated when we type Ctrl-C .
For the rest of the time, it just sits in an infinite loop,
printing a message once a second. */

int main()
{
(void) signal(SIGINT, ouch);

while(1) {
printf("Hello World!n");
sleep(1);
}
}



使用 Kill 函數發送 signal 給另外一個 process

pause 函數會暫停 process 執行,直到收到任何一個 signal

alarm.c

/* In alarm.c, the first function, ding, simulates an alarm clock. */

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

static int alarm_fired = 0;

void ding(int sig)
{
alarm_fired = 1;
}

/* In main, we tell the child process to wait for five seconds
before sending a SIGALRM signal to its parent. */

int main()
{
int pid;

printf("alarm application startingn");

if((pid = fork()) == 0) {
sleep(5);
kill(getppid(), SIGALRM);
exit(0);
}

/* The parent process arranges to catch SIGALRM with a call to signal
and then waits for the inevitable. */

printf("waiting for alarm to go offn");
(void) signal(SIGALRM, ding);

pause();
if (alarm_fired)
printf("Ding!n");

printf("donen");
exit(0);
}



與 signal 註冊函數等效的另一個函數 sigaction

ctrlc2.c

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
printf("OUCH! - I got signal %dn", sig);
}

int main()
{
struct sigaction act;

act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;

sigaction(SIGINT, &act, 0);

while(1) {
printf("Hello World!n");
sleep(1);
}
}

Makefile

# Makefile for applications to demo process API
SYSTEM=system1 system2 pexec
FORK=fork1 wait fork2
FILTER=upper useupper
SIGNALS=ctrlc1 alarm ctrlc2
ALL= $(SYSTEM) $(FORK) $(FILTER) $(SIGNALS)

CROSS_COMPILE = arm-linux-

LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR

#
# Include the make variables (CC, etc...)
#

AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar

export AS LD CC CPP AR

CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.

#OBJS= mutex_thd1.o
#EXEC = mutex_thd1
#$(EXEC): $(OBJS)
# $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

all: $(ALL)

.c.o:
$(CC) $(CFLAGS) -c -o $@ $<

.S.o:
$(CC) $(AFLAGS) -c -o $@ $<


system1: system1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

system2: system2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pexec: pexec.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

fork1: fork1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

wait: wait.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

fork2: fork2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

upper: upper.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

useupper: useupper.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

ctrlc1: ctrlc1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

alarm: alarm.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

ctrlc2: ctrlc2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

.PHONY : clean
clean:
rm -f $(EXEC) *.bin *.elf *.o *.s *.gdb *.bak *.*~

星期六, 5月 12, 2007

Thread API

V1.0

copyright@2006

email: mesmerli@hotmail.com

前言

本文說明 Linux 下,與 Thread 相關之 API


pthread_create 建立子執行緒

pthread_join 等待子執行緒結束,以得到返回值,並回收子執行緒資源

pthread_exit 結束一個執行緒,並將返回值傳給父執行緒

pthread_attr_setdetachstate 讓子執行緒執行結束後,不必等待父執行緒讀取返回值,即由作業系統回收所佔用的資源

sem_init 建立 semaphore (與 process 之 semaphore 不可混用)

sem_wait 若 semaphore 的內含值大於0,則內含值減1後繼續執行,否則執行緒暫停執行直到內含值大於0

sem_post 將 semaphore 的內含值加1,並喚醒等待中的執行緒

sem_destroy 回收 semaphore 所佔用的資源

pthread_mutex_init 建立 mutex,mutex 為 Semaphore 內含值等於 1 的特例

pthread_mutex_lock 若 mutex 的內含值大於0,則內含值減1後繼續執行,否則執行緒暫停執行直到內含值大於0

pthread_mutex_unlock 將 mutex 的內含值加1,並喚醒等待中的執行緒

pthread_mutex_destroy 回收 mutex 所佔用的資源



thread1.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);

char message[] = "Hello World";

int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined, it returned %sn", (char *)thread_result);
printf("Message is now %sn", message);
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
printf("thread_function is running. Argument was %sn", (char *)arg);
sleep(3);
strcpy(message, "Bye!");
pthread_exit("Thank you for the CPU time");
}

thread2.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);
int run_now = 1;
char message[] = "Hello World";

int main() {
int res;
pthread_t a_thread;
void *thread_result;
int print_count1 = 0;

res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}

while(print_count1++ < 20) {
if (run_now == 1) {
printf("1");
run_now = 2;
}
else {
sleep(1);
}
}

printf("nWaiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joinedn");
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
int print_count2 = 0;

while(print_count2++ < 20) {
if (run_now == 2) {
printf("2");
run_now = 1;
}
else {
sleep(1);
}
}

sleep(3);
}

thread3.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

void *thread_function(void *arg);
sem_t bin_sem;

#define WORK_SIZE 1024
char work_area[WORK_SIZE];

int main() {
int res;
pthread_t a_thread;
void *thread_result;

res = sem_init(&bin_sem, 0, 0);
if (res != 0) {
perror("Semaphore initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Input some text. Enter 'end' to finishn");
while(strncmp("end", work_area, 3) != 0) {
fgets(work_area, WORK_SIZE, stdin);
sem_post(&bin_sem);
}
printf("nWaiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joinedn");
sem_destroy(&bin_sem);
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
sem_wait(&bin_sem);
while(strncmp("end", work_area, 3) != 0) {
printf("You input %d charactersn", strlen(work_area) -1);
sem_wait(&bin_sem);
}
pthread_exit(NULL);
}

thread3a.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

void *thread_function(void *arg);
sem_t bin_sem;

#define WORK_SIZE 1024
char work_area[WORK_SIZE];

int main() {
int res;
pthread_t a_thread;
void *thread_result;

res = sem_init(&bin_sem, 0, 0);
if (res != 0) {
perror("Semaphore initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}

printf("Input some text. Enter 'end' to finishn");
while(strncmp("end", work_area, 3) != 0) {
if (strncmp(work_area, "FAST", 4) == 0) {
sem_post(&bin_sem);
strcpy(work_area, "Wheeee...");
} else {
fgets(work_area, WORK_SIZE, stdin);
}
sem_post(&bin_sem);
}

printf("nWaiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joinedn");
sem_destroy(&bin_sem);
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
sem_wait(&bin_sem);
while(strncmp("end", work_area, 3) != 0) {
printf("You input %d charactersn", strlen(work_area) -1);
sem_wait(&bin_sem);
}
pthread_exit(NULL);
}

thread4.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */

#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;

int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);
printf("Input some text. Enter 'end' to finishn");
while(!time_to_exit) {
fgets(work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
while(1) {
pthread_mutex_lock(&work_mutex);
if (work_area[0] != '0') {
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
else {
break;
}
}
}
pthread_mutex_unlock(&work_mutex);
printf("nWaiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joinedn");
pthread_mutex_destroy(&work_mutex);
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
sleep(1);
pthread_mutex_lock(&work_mutex);
while(strncmp("end", work_area, 3) != 0) {
printf("You input %d charactersn", strlen(work_area) -1);
work_area[0] = '0';
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
while (work_area[0] == '0' ) {
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit = 1;
work_area[0] = '0';
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}

thread5.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);

char message[] = "Hello World";
int thread_finished = 0;

int main() {
int res;
pthread_t a_thread;
void *thread_result;
pthread_attr_t thread_attr;

res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
(void)pthread_attr_destroy(&thread_attr);
while(!thread_finished) {
printf("Waiting for thread to say it's finished...n");
sleep(1);
}
printf("Other thread finished, bye!n");
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
printf("thread_function is running. Argument was %sn", (char *)arg);
sleep(4);
printf("Second thread setting finished flag, and exiting nown");
thread_finished = 1;
pthread_exit(NULL);
}

thread6.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);

char message[] = "Hello World";
int thread_finished = 0;

int main() {
int res;
pthread_t a_thread;
void *thread_result;
pthread_attr_t thread_attr;

int max_priority;
int min_priority;
struct sched_param scheduling_value;

res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setschedpolicy(&thread_attr, SCHED_OTHER);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
max_priority = sched_get_priority_max(SCHED_OTHER);
min_priority = sched_get_priority_min(SCHED_OTHER);
scheduling_value.sched_priority = min_priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
(void)pthread_attr_destroy(&thread_attr);
while(!thread_finished) {
printf("Waiting for thread to say it's finished...n");
sleep(1);
}
printf("Other thread finished, bye!n");
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
printf("thread_function is running. Argument was %sn", (char *)arg);
sleep(4);
printf("Second thread setting finished flag, and exiting nown");
thread_finished = 1;
pthread_exit(NULL);
}

thread6a.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <pthread.h>

#ifndef _POSIX_THREAD_PRIORITY_SCHEDULING
#error "Sorry, your system does not support thread priority scheduling"
#endif

void *thread_function(void *arg);

char message[] = "Hello World";
int thread_finished = 0;

int main() {

int res;
pthread_t a_thread;
void *thread_result;
int max_priority, min_priority;
struct sched_param scheduling_value;

pthread_attr_t thread_attr;

res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed");
exit(EXIT_FAILURE);
}

res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}

res = pthread_attr_setschedpolicy(&thread_attr, SCHED_OTHER);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}

max_priority = sched_get_priority_max(SCHED_OTHER);
min_priority = sched_get_priority_min(SCHED_OTHER);
scheduling_value.sched_priority = min_priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
printf("Scheduling priority set to %d, max allowed was %dn", min_priority, max_priority);

res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}

(void)pthread_attr_destroy(&thread_attr);

while(!thread_finished) {
printf("Waiting for thread...n");
sleep(1);
}
printf("Thread finished, bye!n");

exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {

printf("thread_function is running. Argument was %sn", (char *)arg);
sleep(4);

thread_finished = 1;
pthread_exit(NULL);
}


thread7.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);

int main() {
int res;
pthread_t a_thread;
void *thread_result;

res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep(3);
printf("Canceling thread...n");
res = pthread_cancel(a_thread);
if (res != 0) {
perror("Thread cancelation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
int i, res, j;
res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (res != 0) {
perror("Thread pthread_setcancelstate failed");
exit(EXIT_FAILURE);
}
res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
if (res != 0) {
perror("Thread pthread_setcanceltype failed");
exit(EXIT_FAILURE);
}
printf("thread_function is runningn");
for(i = 0; i < 10; i++) {
printf("Thread is still running (%d)...n", i);
sleep(1);
}
pthread_exit(0);
}

thread8.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_THREADS 6

void *thread_function(void *arg);

int main() {
int res;
pthread_t a_thread[NUM_THREADS];
void *thread_result;
int lots_of_threads;

for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) {

res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)&lots_of_threads);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
sleep(1);
}
printf("Waiting for threads to finish...n");
for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
res = pthread_join(a_thread[lots_of_threads], &thread_result);
if (res == 0) {
printf("Picked up a threadn");
}
else {
perror("pthread_join failed");
}
}
printf("All donen");
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
int my_number = *(int *)arg;
int rand_num;

printf("thread_function is running. Argument was %dn", my_number);
rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));
sleep(rand_num);
printf("Bye from %dn", my_number);
pthread_exit(NULL);
}

thread8a.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <pthread.h>

#define NUM_THREADS 6

void *thread_function(void *arg);

int main() {

int res;
pthread_t a_thread[NUM_THREADS];
void *thread_result;
int lots_of_threads;

for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) {

res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)lots_of_threads);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
/* sleep(1); */
}

printf("Waiting for threads to finish...n");
for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
res = pthread_join(a_thread[lots_of_threads], &thread_result);
if (res == 0) {
printf("Picked up a threadn");
} else {
perror("pthread_join failed");
}
}

printf("All donen");

exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
int my_number = (int)arg;
int rand_num;

printf("thread_function is running. Argument was %dn", my_number);
rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));
sleep(rand_num);
printf("Bye from %dn", my_number);

pthread_exit(NULL);
}

Makefile

CROSS_COMPILE = arm-linux-

LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR

#
# Include the make variables (CC, etc...)
#

AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar

export AS LD CC CPP AR

CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.

.c.o:
$(CC) $(CFLAGS) -c -o $@ $<

.S.o:
$(CC) $(AFLAGS) -c -o $@ $<

all: thread1 thread2 thread3 thread3a thread4 thread5 thread6 thread7 thread8 thread8a

thread1: thread1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread2: thread2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread3: thread3.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread3a: thread3a.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread4: thread4.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread5: thread5.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread6: thread6.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread7: thread7.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread8: thread8.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

thread8a: thread8a.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

clean:
rm -f thread1 thread2 thread3 thread3a thread4 thread5 thread6 thread7 thread7a thread8 thread8a


PIPE FIFO API

V1.0

copyright@2006

email: mesmerli@hotmail.com

前言

本文介紹 Linux 下,與 PIPE 與 FIFO 相關 API。

PIPE

PIPE 常用在輸出入的轉向。在 Linux 下使用 PIPE 有兩類 API:

  1. popen:較簡單
  2. pipe:適合進階應用

FIFO

FIFO 使用前,需要建立一個 FIFO node 在檔案系統中。可以使用以下命令建立:

  1. mknod MYFIFO p
  2. mkfifo a=rw MYFIFO

使用 popen 函數將外部程式的輸出,轉向到一個 file handler 供主程式處理

popen1.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, '0', sizeof(buffer));
read_fp = popen("uname -a", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
if (chars_read > 0) {
printf("Output was:-n%sn", buffer);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}


使用 popen 函數,讓外部程式的輸入,透過主程式供應

popen2.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
FILE *write_fp;
char buffer[BUFSIZ + 1];

sprintf(buffer, "Once upon a time, there was...n");
write_fp = popen("od -c", "w");
if (write_fp != NULL) {
fwrite(buffer, sizeof(char), strlen(buffer), write_fp);
pclose(write_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}

popen3.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;


memset(buffer, '0', sizeof(buffer));
read_fp = popen("ps -ax", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
while (chars_read > 0) {
buffer[chars_read - 1] = '0';
printf("Reading:-n %sn", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}

popen4.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;


memset(buffer, '0', sizeof(buffer));
read_fp = popen("cat popen*.c | wc -l", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
while (chars_read > 0) {
buffer[chars_read - 1] = '0';
printf("Reading:-n %sn", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}


使用 pipe 函數,註冊一組 pipe。 裡面有兩個 file handler。

當寫入 file handler 1,資料可以從 file handler 0 讀出

pipe1.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];

memset(buffer, '0', sizeof(buffer));

if (pipe(file_pipes) == 0) {
data_processed = write(file_pipes[1], some_data, strlen(some_data));
printf("Wrote %d bytesn", data_processed);
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf("Read %d bytes: %sn", data_processed, buffer);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}



建立兩個 process,並在兩個 process 之間透過 pipe 傳遞資料

pipe2.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];
pid_t fork_result;

memset(buffer, '0', sizeof(buffer));

if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == -1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}

// We've made sure the fork worked, so if fork_result equals zero, we're in the child process.

if (fork_result == 0) {
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf("Read %d bytes: %sn", data_processed, buffer);
exit(EXIT_SUCCESS);
}

// Otherwise, we must be the parent process.

else {
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
printf("Wrote %d bytesn", data_processed);
}
}
exit(EXIT_SUCCESS);
}


pipe3 與 pipe4 是一組共同實驗的程式,pipe3 執行外部程式 pipe4,並透過 pipe 傳遞資料給 pipe4

pipe3.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];
pid_t fork_result;

memset(buffer, '0', sizeof(buffer));

if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == (pid_t)-1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}

if (fork_result == 0) {
sprintf(buffer, "%d", file_pipes[0]);
(void)execl("pipe4", "pipe4", buffer, (char *)0);
exit(EXIT_FAILURE);
}
else {
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
printf("%d - wrote %d bytesn", getpid(), data_processed);
}
}
exit(EXIT_SUCCESS);
}

pipe4.c

// The 'consumer' program, pipe4.c, that reads the data is much simpler.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
int data_processed;
char buffer[BUFSIZ + 1];
int file_descriptor;

memset(buffer, '0', sizeof(buffer));
sscanf(argv[1], "%d", &file_descriptor);
data_processed = read(file_descriptor, buffer, BUFSIZ);

printf("%d - read %d bytes: %sn", getpid(), data_processed, buffer);
exit(EXIT_SUCCESS);
}



使用 pipe 轉向 stdin,讓主程式提供外部程式的輸入

pipe5.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
pid_t fork_result;

if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == (pid_t)-1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}

if (fork_result == (pid_t)0) {
close(0);
dup(file_pipes[0]);
close(file_pipes[0]);
close(file_pipes[1]);

execlp("od", "od", "-c", (char *)0);
exit(EXIT_FAILURE);
}
else {
close(file_pipes[0]);
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
close(file_pipes[1]);
printf("%d - wrote %d bytesn", (int)getpid(), data_processed);
}
}
exit(EXIT_SUCCESS);
}



利用 mkfifo 在檔案系統上建立 fifo 節點

fifo1.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
int res = mkfifo("/tmp/my_fifo", 0777);
if (res == 0)
printf("FIFO createdn");
exit(EXIT_SUCCESS);
}



使用不同的模式開啟檔案系統上的 fifo 檔案

fifo2.c

// Let's start with the header files, a #define and the check that the correct number
// of command-line arguments have been supplied.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/my_fifo"

int main(int argc, char *argv[])
{
int res;
int open_mode = 0;
int i;

if (argc < 2) {
fprintf(stderr, "Usage: %s <some combination of
O_RDONLY O_WRONLY O_NONBLOCK>n", *argv);
exit(EXIT_FAILURE);
}

// Assuming that the program passed the test, we now set the value of open_mode
// from those arguments.

for(i = 1; i < argc; i++) {
if (strncmp(*++argv, "O_RDONLY", 8) == 0)
open_mode |= O_RDONLY;
if (strncmp(*argv, "O_WRONLY", 8) == 0)
open_mode |= O_WRONLY;
if (strncmp(*argv, "O_NONBLOCK", 10) == 0)
open_mode |= O_NONBLOCK;
}

// We now check whether the FIFO exists and create it if necessary.
// Then the FIFO is opened and output given to that effect while the program
// catches forty winks. Last of all, the FIFO is closed.

if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %sn", FIFO_NAME);
exit(EXIT_FAILURE);
}
}

printf("Process %d opening FIFOn", getpid());
res = open(FIFO_NAME, open_mode);
printf("Process %d result %dn", getpid(), res);
sleep(5);
if (res != -1) (void)close(res);
printf("Process %d finishedn", getpid());
exit(EXIT_SUCCESS);
}



fifo3 與 fifo4 為一組共同實驗的程式,fifo3 傳遞資料給 fifo4

fifo3.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define PIPE_BUF 4096

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)

int main()
{
int pipe_fd;
int res;
int open_mode = O_WRONLY;
int bytes_sent = 0;
char buffer[BUFFER_SIZE + 1];

if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %sn", FIFO_NAME);
exit(EXIT_FAILURE);
}
}

printf("Process %d opening FIFO O_WRONLYn", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %dn", getpid(), pipe_fd);

if (pipe_fd != -1) {
while(bytes_sent < TEN_MEG) {
res = write(pipe_fd, buffer, BUFFER_SIZE);
if (res == -1) {
fprintf(stderr, "Write error on pipen");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}

printf("Process %d finishedn", getpid());
exit(EXIT_SUCCESS);
}

fifo4.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define PIPE_BUF 4096

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF

int main()
{
int pipe_fd;
int res;
int open_mode = O_RDONLY;
char buffer[BUFFER_SIZE + 1];
int bytes_read = 0;

memset(buffer, '0', sizeof(buffer));

printf("Process %d opening FIFO O_RDONLYn", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %dn", getpid(), pipe_fd);

if (pipe_fd != -1) {
do {
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > 0);
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}

printf("Process %d finished, %d bytes readn", getpid(), bytes_read);
exit(EXIT_SUCCESS);
}

Makefile

CROSS_COMPILE = arm-linux-

LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR

#
# Include the make variables (CC, etc...)
#

AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar

export AS LD CC CPP AR

CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.

.c.o:
$(CC) $(CFLAGS) -c -o $@ $<

.S.o:
$(CC) $(AFLAGS) -c -o $@ $<

all: fifo1 fifo2 fifo3 fifo4 pipe1 pipe2 pipe3 pipe4 pipe5 popen1 popen2 popen3 popen4

fifo1: fifo1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

fifo2: fifo2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

fifo3: fifo3.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

fifo4: fifo4.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pipe1: pipe1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pipe2: pipe2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pipe3: pipe3.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pipe4: pipe4.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

pipe5: pipe5.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

popen1: popen1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

popen2: popen2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

popen3: popen3.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

popen4: popen4.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

#client.o: client.h
#server.o: client.h

clean:
rm -f fifo1 fifo2 fifo3 fifo4 pipe1 pipe2 pipe3 pipe4 pipe5 popen1 popen2 popen3 popen4 client server /tmp/my_fifo *.o

IPC API

V1.0

copyright@2006

email: mesmerli@hotmail.com

前言

本文介紹 Linux 下,IPC 相關的 API。

  1. Semaphone: 本文介紹的是使用於Process 之間的同步機制,注意 pthread 與 process 使用不同的 API。
  2. Shared Memory: 利用共享記憶體機制於 Process 之間傳遞訊息。
  3. Message: 利用信箱機制於 Process 之間傳遞訊息。


使用 semget 建立 semaphone,每個 semaphore 使用 key 值識別。

相同的 key 值的 semaphone,在不同的 process 之間視為相同的 semaphore

sem1.c

/* After the #includes, the function prototypes and the global variable, we come to the
main function. There the semaphore is created with a call to semget, which returns the
semaphore ID. If the program is the first to be called (i.e. it's called with a parameter
and argc > 1), a call is made to set_semvalue to initialize the semaphore and op_char is
set to X. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include "semun.h"

static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void);

static int sem_id;


int main(int argc, char *argv[])
{
int i;
int pause_time;
char op_char = 'O';

srand((unsigned int)getpid());

sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);

if (argc > 1) {
if (!set_semvalue()) {
fprintf(stderr, "Failed to initialize semaphoren");
exit(EXIT_FAILURE);
}
op_char = 'X';
sleep(2);
}

/* Then we have a loop which enters and leaves the critical section ten times.
There, we first make a call to semaphore_p which sets the semaphore to wait, as
this program is about to enter the critical section. */

for(i = 0; i < 10; i++) {

if (!semaphore_p()) exit(EXIT_FAILURE);
printf("%c", op_char);fflush(stdout);
pause_time = rand() % 3;
sleep(pause_time);
printf("%c", op_char);fflush(stdout);

/* After the critical section, we call semaphore_v, setting the semaphore available,
before going through the for loop again after a random wait. After the loop, the call
to del_semvalue is made to clean up the code. */

if (!semaphore_v()) exit(EXIT_FAILURE);

pause_time = rand() % 2;
sleep(pause_time);
}

printf("n%d - finishedn", getpid());

if (argc > 1) {
sleep(10);
del_semvalue();
}

exit(EXIT_SUCCESS);
}

/* The function set_semvalue initializes the semaphore using the SETVAL command in a
semctl call. We need to do this before we can use the semaphore. */

static int set_semvalue(void)
{
union semun sem_union;

sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
return(1);
}

/* The del_semvalue function has almost the same form, except the call to semctl uses
the command IPC_RMID to remove the semaphore's ID. */

static void del_semvalue(void)
{
union semun sem_union;

if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphoren");
}

/* semaphore_p changes the semaphore by -1 (waiting). */

static int semaphore_p(void)
{
struct sembuf sem_b;

sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_p failedn");
return(0);
}
return(1);
}

/* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
so that the semaphore becomes available. */

static int semaphore_v(void)
{
struct sembuf sem_b;

sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_v failedn");
return(0);
}
return(1);
}


使用 shmget 建立 shared memory 每個 shared memory 使用 key 值識別。

相同的 key 值的 shared memory 在不同的 process 之間視為相同的 shared memory

shm1.c

/* Our first program is a consumer. After the headers the shared memory segment
(the size of our shared memory structure) is created with a call to shmget,
with the IPC_CREAT bit specified. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include "shm_com.h"

int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
int shmid;

srand((unsigned int)getpid());

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);

if (shmid == -1) {
fprintf(stderr, "shmget failedn");
exit(EXIT_FAILURE);
}

/* We now make the shared memory accessible to the program. */

shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failedn");
exit(EXIT_FAILURE);
}

printf("Memory attached at %Xn", (int)shared_memory);

/* The next portion of the program assigns the shared_memory segment to shared_stuff,
which then prints out any text in written_by_you. The loop continues until end is found
in written_by_you. The call to sleep forces the consumer to sit in its critical section,
which makes the producer wait. */

shared_stuff = (struct shared_use_st *)shared_memory;
shared_stuff->written_by_you = 0;
while(running) {
if (shared_stuff->written_by_you) {
printf("You wrote: %s", shared_stuff->some_text);
sleep( rand() % 4 ); /* make the other process wait for us ! */
shared_stuff->written_by_you = 0;
if (strncmp(shared_stuff->some_text, "end", 3) == 0) {
running = 0;
}
}
}

/* Lastly, the shared memory is detached and then deleted. */

if (shmdt(shared_memory) == -1) {
fprintf(stderr, "shmdt failedn");
exit(EXIT_FAILURE);
}

if (shmctl(shmid, IPC_RMID, 0) == -1) {
fprintf(stderr, "shmctl(IPC_RMID) failedn");
exit(EXIT_FAILURE);
}

exit(EXIT_SUCCESS);
}

shm2.c

/* The second program is the producer and allows us to enter data for consumers.
It's very similar to shm1.c and looks like this. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include "shm_com.h"

int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid;

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);

if (shmid == -1) {
fprintf(stderr, "shmget failedn");
exit(EXIT_FAILURE);
}

shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failedn");
exit(EXIT_FAILURE);
}

printf("Memory attached at %Xn", (int)shared_memory);

shared_stuff = (struct shared_use_st *)shared_memory;
while(running) {
while(shared_stuff->written_by_you == 1) {
sleep(1);
printf("waiting for client...n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);

strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
shared_stuff->written_by_you = 1;

if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}

if (shmdt(shared_memory) == -1) {
fprintf(stderr, "shmdt failedn");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}



使用 msgget 建立 message queue 每個 message queue 使用 key 值識別。

相同的 key 值的 message queue 在不同的 process 之間視為相同的 message queue

msg1.c

/* Here's the receiver program. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};

int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;

/* First, we set up the message queue. */

msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %dn", errno);
exit(EXIT_FAILURE);
}

/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */

while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %dn", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}

if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failedn");
exit(EXIT_FAILURE);
}

exit(EXIT_SUCCESS);
}

msg2.c

/* The sender program is very similar to msg1.c. In the main set up, delete the
msg_to_receive declaration and replace it with buffer[BUFSIZ], remove the message
queue delete and make the following changes to the running loop.
We now have a call to msgsnd to send the entered text to the queue. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MAX_TEXT 512

struct my_msg_st {
long int my_msg_type;
char some_text[MAX_TEXT];
};

int main()
{
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];

msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %dn", errno);
exit(EXIT_FAILURE);
}

while(running) {
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);

if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failedn");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}

exit(EXIT_SUCCESS);
}

Makefile

CROSS_COMPILE = arm-linux-

LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR

#
# Include the make variables (CC, etc...)
#

AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar

export AS LD CC CPP AR

CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.

.c.o:
$(CC) $(CFLAGS) -c -o $@ $<

.S.o:
$(CC) $(AFLAGS) -c -o $@ $<

all: msg1 msg2 shm1 shm2 sem1

sem1.c: semun.h
shm1.c: shm_com.h
shm2.c: shm_com.h

msg1: msg1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

msg2: msg2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

shm1: shm1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

shm2: shm2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

sem1: sem1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

clean:
rm -f msg1 msg2 shm1 shm2 sem1

建構除錯版的應用程式

V1.0

copyright@2006

email: mesmerli@hotmail.com

建構應用程式

本文實際搭配 gdbserver 6.1 與 Insight 6.1 成功驗證遠端應用程式除錯。

依下文建立以下兩個檔案:

  1. Makefile
  2. hello.c

接下來使用以下命令,編譯建構應用程式。

#make -f Makefile

Makefile

# Makefile to build application for gdbserver and Insight
SYSTEM=helloworld
ALL= $(SYSTEM)

CROSS_COMPILE = arm-linux-

LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR

#
# Include the make variables (CC, etc...)
#

AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar

export AS LD CC CPP AR

CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.

#OBJS= mutex_thd1.o
#EXEC = mutex_thd1
#$(EXEC): $(OBJS)
# $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

all: $(ALL)

.c.o:
$(CC) $(CFLAGS) -c -o $@ $<

.S.o:
$(CC) $(AFLAGS) -c -o $@ $<


helloworld: helloworld.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a

.PHONY : clean
clean:
rm -f $(EXEC) *.bin *.elf *.o *.s *.gdb *.bak *.*~

hello.c

#include <stdio.h>

int main(void)
{
int i;
for(i=0; i<101; i++)
{
printf("Hello world %d times!n", i);
}
}