Linux Kernel 原始碼有一個 list.h , 它位於 linux/list.h . 它不只是在 kernel 可以使用, 在 linux user space 下也可以使用, 甚至於是 windows programming 也可以使用. 因為蠻好用的, 所以我把它介紹出來. 筆者會提供一個不錯的範例程式來介紹 list.h 裡面的 inline 函式 (巨集) 的使用方法; 這些 inline 函式 (巨集) 包括了:
1. INIT_LIST_HEAD(ptr);
2. void list_add_tail(struct list_head *neu, struct list_head *head);
3. void list_del(struct list_head *entry);
4. list_for_each_safe(pos, n, head)
5. list_entry(ptr, type, member)
思考步驟:
I. 首先你當然必須要 include "list.h" .
II. Global 變數 pl; 它是一個 list. 它是一個包含 struct list_head list 成員的結構. 另一個成員是 unsigned char c;
static struct pool_t {
struct list_head list;
unsigned char c;
} pl;
III. 在一切還未開始之前 呼叫
INIT_LIST_HEAD(&pl.list);
IV. 範例裡面包含了一個 Producer 執行緒 (main) 以及一個 Consumer 執行緒 (emit) . Producer 執行緒首先 allocate 一個 node (struct pool_t) ; 第2步是填上 node, e->c=ch; 第3步是將這個 node 使用 list_add_tail() 插入 pl 這個 list 的尾巴.
e = (struct pool_t *)malloc(sizeof(struct pool_t)); e->c = ch;
list_add_tail(&e->list, &pl.list);
V. Consumer 執行緒則是使用 list_for_each_safe() 巨集將 pl 裡面的每一個 node 拷貝出; 之後使用 list_del() 取出 (pop out) ; 最後是 free Producer allocate 之 memory. 注意: 在這裡一定要使用 list_for_each_safe() 而不能使用 list_for_each() , 原因是 我們在這個迴圈中使用了 list_del() .
n = 0;
list_for_each_safe(pos, q, &pl.list) {
e = list_entry(pos, struct pool_t, list);
memcpy(&buffer[n++], &e->c, sizeof(unsigned char));
list_del(pos)
free(e);
}
poolEmpty = 1;
VI. Threads 存取同一個 linked list 當然需要同步機制. 因此我們宣告 cPoolEmpty 條件變數, mPoolEmpty 互斥子以及 poolEmpty這個用來說明條件變數是否為真之 Predication.
static pthread_cond_t cPoolEmpty;
static int poolEmpty = 1;
static pthread_mutex_t mPoolEmpty = PTHREAD_MUTEX_INITIALIZER;
VII. Consumer 執行緒當然是靜靜地等待 Producer 執行緒的通知.
WAIT:
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
while (poolEmpty) pthread_cond_wait(&cPoolEmpty, &mPoolEmpty);
pthread_cleanup_pop(1);
VIII. Consumer 執行緒被喚醒之後:
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
n = 0;
list_for_each_safe(pos, q, &pl.list) {
e = list_entry(pos, struct pool_t, list); memcpy(&buffer[n++], &e->c, sizeof(unsigned char)); list_del(pos), free(e);
}
poolEmpty = 1;
pthread_cleanup_pop(1);
VIIII. 當 pl 不是 empty 時, Producer 執行緒 TELL Consumer 執行緒.
TELL_WAIT:
poolEmpty = 0; pthread_cond_signal(&cPoolEmpty);
e = (struct pool_t *)malloc(sizeof(struct pool_t));
memcpy(&e->c, &ch, sizeof(ch));
pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty);
list_add_tail(&e->list, &pl.list);
poolEmpty = 0; pthread_cond_signal(&cPoolEmpty);
pthread_cleanup_pop(1);
範例
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdarg.h> #include <stdlib.h> #include <time.h> #include <sys/mount.h> // for mount #include <fcntl.h> #include <signal.h> #include <netinet/tcp.h> #include <inttypes.h> #include <sched.h> #include <assert.h> #include <sys/ioctl.h> #include <ctype.h> #include <termios.h> #include <poll.h> #include <linux/uinput.h> #include <linux/input-event-codes.h> #include <pthread.h> struct pool_t { struct list_head list; unsigned char c; }; static struct pool_t pl; static pthread_t tEmit = 0; static pthread_cond_t cPoolEmpty; static int poolEmpty = 1; static pthread_mutex_t mPoolEmpty = PTHREAD_MUTEX_INITIALIZER; #define TTY_SERIAL "/dev/ttyMK0" #define SELECT_EXPIRY_NINISECONDS 100ULL #define ACTION_DOWN 1 #define ACTION_UP 0 #define _u1_ 0 #define _d1_ 1 #define _l1_ 2 #define _r1_ 3 #define _s1_ 4 #define _x1_ 5 #define _y1_ 6 #define _z1_ 7 #define _a1_ 8 #define _b1_ 9 #define _c1_ 10 #define _u2_ 11 #define _d2_ 12 #define _l2_ 13 #define _r2_ 14 #define _s2_ 15 #define _x2_ 16 #define _y2_ 17 #define _z2_ 18 #define _a2_ 19 #define _b2_ 20 #define _c2_ 21 #define _m_ 22 #define _w_ 23 #define _U1_ (1 << _u1_) #define _D1_ (1 << _d1_) #define _L1_ (1 << _l1_) #define _R1_ (1 << _r1_) #define _S1_ (1 << _s1_) #define _X1_ (1 << _x1_) #define _Y1_ (1 << _y1_) #define _Z1_ (1 << _z1_) #define _A1_ (1 << _a1_) #define _B1_ (1 << _b1_) #define _C1_ (1 << _c1_) #define _U2_ (1 << _u2_) #define _D2_ (1 << _d2_) #define _L2_ (1 << _l2_) #define _R2_ (1 << _r2_) #define _S2_ (1 << _s2_) #define _X2_ (1 << _x2_) #define _Y2_ (1 << _y2_) #define _Z2_ (1 << _z2_) #define _A2_ (1 << _a2_) #define _B2_ (1 << _b2_) #define _C2_ (1 << _c2_) #define _M_ (1 << _m_) #define _W_ (1 << _w_) struct code_t { int index; int code; const char *name; }; static struct code_t keypad_codes[] = { {_u1_, KEY_UP, "P1_UP"}, {_d1_, KEY_DOWN, "P1_DW"}, {_l1_, KEY_LEFT, "P1_LF"}, {_r1_, KEY_RIGHT, "P1_RG"}, {_s1_, KEY_ENTER, "P1_ST"}, {_x1_, KEY_X, "P1_X "}, {_y1_, KEY_Y, "P1_Y "}, {_z1_, KEY_Z, "P1_Z "}, {_a1_, KEY_A, "P1_A "}, {_b1_, KEY_B, "P1_B "}, {_c1_, KEY_C, "P1_C "}, {_u2_, KEY_KP8, "P2_UP"}, {_d2_, KEY_KP2, "P2_DW"}, {_l2_, KEY_KP4, "P2_LF"}, {_r2_, KEY_KP6, "P2_RG"}, {_s2_, KEY_SPACE, "P2_ST"}, {_x2_, KEY_F4, "P2_X "}, {_y2_, KEY_F5, "P2_Y "}, {_z2_, KEY_F6, "P2_Z "}, {_a2_, KEY_F1, "P2_A "}, {_b2_, KEY_F8, "P2_B "}, {_c2_, KEY_F3, "P2_C "}, {_m_, KEY_M, "MD"}, {_w_, KEY_R, "RW"}, }; #define KEYPAD_KEYNUMBER (sizeof(keypad_codes)/sizeof(struct code_t)) static unsigned int uartNowEvents = 0; static int uinputfd = -1; static int ttyfd = -1; static char ttyLine[1024] = {0}; static int ttyLineLength = 0; #define PRINTF(f_, ...) \ sprintf(ttyLine, f_, ##__VA_ARGS__), \ ttyLineLength = strlen(ttyLine), \ ttyLine[ttyLineLength] = 0, \ write(ttyfd, (void *)ttyLine, ttyLineLength + 1) static void emit(int fd, int type, int code, int val) { struct input_event ie = {0}; ie.type = type; ie.code = code; ie.value = val; write(fd, &ie, sizeof(ie)); } static void CleanupLock(void *param) { pthread_mutex_unlock((pthread_mutex_t *)param); } static void *EmitThread(void *param) { unsigned char ch; struct pool_t *e; // entry struct list_head *pos, *q; unsigned char buffer[1024 * 4] = {0}; int n = 0, i = 0; ///////////////////////////// // Wait for somebody tell WAIT: pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); while (poolEmpty) pthread_cond_wait(&cPoolEmpty, &mPoolEmpty); pthread_cleanup_pop(1); ///////////////////////////// // <need-fast> pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); n = 0; list_for_each_safe(pos, q, &pl.list) { e = list_entry(pos, struct pool_t, list); memcpy(&buffer[n++], &e->c, sizeof(unsigned char)); list_del(pos), free(e); } poolEmpty = 1; pthread_cleanup_pop(1); // </need-fast> for (i = 0; i < n; i++) { ch = buffer[i]; if (ch == (unsigned char)'U') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_DOWN); if (ch == (unsigned char)'u') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_UP); if (ch == (unsigned char)'D') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_DOWN); if (ch == (unsigned char)'d') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_UP); if (ch == (unsigned char)'L') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_DOWN); if (ch == (unsigned char)'l') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_UP); if (ch == (unsigned char)'R') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_DOWN); if (ch == (unsigned char)'r') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_UP); if (ch == (unsigned char)'S') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_DOWN); if (ch == (unsigned char)'s') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_UP); if (ch == (unsigned char)'X') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_DOWN); if (ch == (unsigned char)'x') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_UP); if (ch == (unsigned char)'Y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_DOWN); if (ch == (unsigned char)'y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_UP); if (ch == (unsigned char)'Z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_DOWN); if (ch == (unsigned char)'z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_UP); if (ch == (unsigned char)'A') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_DOWN); if (ch == (unsigned char)'a') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_UP); if (ch == (unsigned char)'B') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_DOWN); if (ch == (unsigned char)'b') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_UP); if (ch == (unsigned char)'C') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_DOWN); if (ch == (unsigned char)'c') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_UP); if (ch == (unsigned char)'H') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_DOWN); if (ch == (unsigned char)'h') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_UP); if (ch == (unsigned char)'I') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_DOWN); if (ch == (unsigned char)'i') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_UP); if (ch == (unsigned char)'J') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_DOWN); if (ch == (unsigned char)'j') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_UP); if (ch == (unsigned char)'K') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_DOWN); if (ch == (unsigned char)'k') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_UP); if (ch == (unsigned char)'T') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_DOWN); if (ch == (unsigned char)'t') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_UP); if (ch == (unsigned char)'O') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_DOWN); if (ch == (unsigned char)'o') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_UP); if (ch == (unsigned char)'P') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_DOWN); if (ch == (unsigned char)'p') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_UP); if (ch == (unsigned char)'Q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_DOWN); if (ch == (unsigned char)'q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_UP); if (ch == (unsigned char)'G') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_DOWN); if (ch == (unsigned char)'g') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_UP); if (ch == (unsigned char)'E') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_DOWN); if (ch == (unsigned char)'e') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_UP); if (ch == (unsigned char)'F') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_DOWN); if (ch == (unsigned char)'f') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_UP); if (ch == (unsigned char)'M') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_DOWN); if (ch == (unsigned char)'m') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_UP); if (ch == (unsigned char)'W') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_DOWN); if (ch == (unsigned char)'w') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_UP); emit(uinputfd, EV_SYN, SYN_REPORT, 0); ///////////////////////////// // 1 mini-second interval usleep(1); } goto WAIT; return 0; } static void onUartChar(unsigned char ch) { struct pool_t *e; if (ch != (unsigned char)'u' && ch != (unsigned char)'U' && ch != (unsigned char)'d' && ch != (unsigned char)'D' && ch != (unsigned char)'l' && ch != (unsigned char)'L' && ch != (unsigned char)'r' && ch != (unsigned char)'R' && ch != (unsigned char)'s' && ch != (unsigned char)'S' && ch != (unsigned char)'x' && ch != (unsigned char)'X' && ch != (unsigned char)'y' && ch != (unsigned char)'Y' && ch != (unsigned char)'z' && ch != (unsigned char)'Z' && ch != (unsigned char)'a' && ch != (unsigned char)'A' && ch != (unsigned char)'b' && ch != (unsigned char)'B' && ch != (unsigned char)'c' && ch != (unsigned char)'C' && ch != (unsigned char)'h' && ch != (unsigned char)'H' && ch != (unsigned char)'i' && ch != (unsigned char)'I' && ch != (unsigned char)'j' && ch != (unsigned char)'J' && ch != (unsigned char)'k' && ch != (unsigned char)'K' && ch != (unsigned char)'t' && ch != (unsigned char)'T' && ch != (unsigned char)'o' && ch != (unsigned char)'O' && ch != (unsigned char)'p' && ch != (unsigned char)'P' && ch != (unsigned char)'q' && ch != (unsigned char)'Q' && ch != (unsigned char)'g' && ch != (unsigned char)'G' && ch != (unsigned char)'e' && ch != (unsigned char)'E' && ch != (unsigned char)'f' && ch != (unsigned char)'F' && ch != (unsigned char)'m' && ch != (unsigned char)'M' && ch != (unsigned char)'w' && ch != (unsigned char)'W' ) return; if (ch == (unsigned char)'u') { uartNowEvents &= ~_U1_; goto TELL_WAIT; } if (ch == (unsigned char)'d') { uartNowEvents &= ~_D1_; goto TELL_WAIT; } if (ch == (unsigned char)'l') { uartNowEvents &= ~_L1_; goto TELL_WAIT; } if (ch == (unsigned char)'r') { uartNowEvents &= ~_R1_; goto TELL_WAIT; } if (ch == (unsigned char)'s') { uartNowEvents &= ~_S1_; goto TELL_WAIT; } if (ch == (unsigned char)'x') { uartNowEvents &= ~_X1_; goto TELL_WAIT; } if (ch == (unsigned char)'y') { uartNowEvents &= ~_Y1_; goto TELL_WAIT; } if (ch == (unsigned char)'z') { uartNowEvents &= ~_Z1_; goto TELL_WAIT; } if (ch == (unsigned char)'a') { uartNowEvents &= ~_A1_; goto TELL_WAIT; } if (ch == (unsigned char)'b') { uartNowEvents &= ~_B1_; goto TELL_WAIT; } if (ch == (unsigned char)'c') { uartNowEvents &= ~_C1_; goto TELL_WAIT; } if (ch == (unsigned char)'U') { uartNowEvents |= _U1_; goto TELL_WAIT; } if (ch == (unsigned char)'D') { uartNowEvents |= _D1_; goto TELL_WAIT; } if (ch == (unsigned char)'L') { uartNowEvents |= _L1_; goto TELL_WAIT; } if (ch == (unsigned char)'R') { uartNowEvents |= _R1_; goto TELL_WAIT; } if (ch == (unsigned char)'S') { uartNowEvents |= _S1_; goto TELL_WAIT; } if (ch == (unsigned char)'X') { uartNowEvents |= _X1_; goto TELL_WAIT; } if (ch == (unsigned char)'Y') { uartNowEvents |= _Y1_; goto TELL_WAIT; } if (ch == (unsigned char)'Z') { uartNowEvents |= _Z1_; goto TELL_WAIT; } if (ch == (unsigned char)'A') { uartNowEvents |= _A1_; goto TELL_WAIT; } if (ch == (unsigned char)'B') { uartNowEvents |= _B1_; goto TELL_WAIT; } if (ch == (unsigned char)'C') { uartNowEvents |= _C1_; goto TELL_WAIT; } if (ch == (unsigned char)'h') { uartNowEvents &= ~_U2_; goto TELL_WAIT; } if (ch == (unsigned char)'i') { uartNowEvents &= ~_D2_; goto TELL_WAIT; } if (ch == (unsigned char)'j') { uartNowEvents &= ~_L2_; goto TELL_WAIT; } if (ch == (unsigned char)'k') { uartNowEvents &= ~_R2_; goto TELL_WAIT; } if (ch == (unsigned char)'t') { uartNowEvents &= ~_S2_; goto TELL_WAIT; } if (ch == (unsigned char)'o') { uartNowEvents &= ~_X2_; goto TELL_WAIT; } if (ch == (unsigned char)'p') { uartNowEvents &= ~_Y2_; goto TELL_WAIT; } if (ch == (unsigned char)'q') { uartNowEvents &= ~_Z2_; goto TELL_WAIT; } if (ch == (unsigned char)'g') { uartNowEvents &= ~_A2_; goto TELL_WAIT; } if (ch == (unsigned char)'e') { uartNowEvents &= ~_B2_; goto TELL_WAIT; } if (ch == (unsigned char)'f') { uartNowEvents &= ~_C2_; goto TELL_WAIT; } if (ch == (unsigned char)'H') { uartNowEvents |= _U2_; goto TELL_WAIT; } if (ch == (unsigned char)'I') { uartNowEvents |= _D2_; goto TELL_WAIT; } if (ch == (unsigned char)'J') { uartNowEvents |= _L2_; goto TELL_WAIT; } if (ch == (unsigned char)'K') { uartNowEvents |= _R2_; goto TELL_WAIT; } if (ch == (unsigned char)'T') { uartNowEvents |= _S2_; goto TELL_WAIT; } if (ch == (unsigned char)'O') { uartNowEvents |= _X2_; goto TELL_WAIT; } if (ch == (unsigned char)'P') { uartNowEvents |= _Y2_; goto TELL_WAIT; } if (ch == (unsigned char)'Q') { uartNowEvents |= _Z2_; goto TELL_WAIT; } if (ch == (unsigned char)'G') { uartNowEvents |= _A2_; goto TELL_WAIT; } if (ch == (unsigned char)'E') { uartNowEvents |= _B2_; goto TELL_WAIT; } if (ch == (unsigned char)'F') { uartNowEvents |= _C2_; goto TELL_WAIT; } if (ch == (unsigned char)'m') { uartNowEvents &= ~_M_; goto TELL_WAIT; } if (ch == (unsigned char)'w') { uartNowEvents &= ~_W_; goto TELL_WAIT; } if (ch == (unsigned char)'M') { uartNowEvents |= _M_; goto TELL_WAIT; } if (ch == (unsigned char)'W') { uartNowEvents |= _W_; goto TELL_WAIT; } TELL_WAIT: e = (struct pool_t *)malloc(sizeof(struct pool_t)); memcpy(&e->c, &ch, sizeof(ch)); pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); list_add_tail(&e->list, &pl.list); poolEmpty = 0; pthread_cond_signal(&cPoolEmpty); pthread_cleanup_pop(1); return; } int main (int argc, char **argv) { struct termios term, save; int res, v, maxfd = 0; fd_set rset; struct timeval tv; struct timespec start_time, now_time; unsigned long long int start, now; struct uinput_user_dev uidev = {0}; int i = 0; char line[512]; uinputfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (0 > uinputfd) exit(1); if (ioctl(uinputfd, UI_SET_EVBIT, EV_KEY) < 0) exit(2); for (i = 0; i < KEYPAD_KEYNUMBER; i++) { if (ioctl(uinputfd, UI_SET_KEYBIT, keypad_codes[i].code) < 0) exit(3); } snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-serial"); uidev.id.bustype = BUS_VIRTUAL, uidev.id.vendor = 0x1, uidev.id.product = 0x1, uidev.id.version = 1; if (write(uinputfd, &uidev, sizeof(uidev)) < 0) exit(4); if(ioctl(uinputfd, UI_DEV_CREATE) < 0) exit(5); sleep(1); ttyfd = open(TTY_SERIAL, O_RDWR | O_NOCTTY | O_NDELAY); if (0 > ttyfd) exit(6); memset(&term, 0, sizeof(struct termios)); if (0 > tcgetattr(ttyfd, &term)) close(ttyfd), ttyfd = -1, exit(7); memcpy((void *)&save, (void *)&term, sizeof(struct termios)); term.c_cflag |= B115200, term.c_cflag |= CLOCAL, term.c_cflag |= CREAD, term.c_cflag &= ~PARENB, term.c_cflag &= ~CSTOPB; term.c_cflag &= ~CSIZE, term.c_cflag |= CS8, term.c_iflag = IGNPAR, term.c_cc[VMIN] = 1, term.c_cc[VTIME] = 0; term.c_iflag = 0, term.c_oflag = 0, term.c_lflag = 0; cfsetispeed(&term, B115200), cfsetospeed(&term, B115200); if (0 > tcsetattr(ttyfd, TCSANOW, &term)) close(ttyfd), ttyfd = -1, exit(8); if (0 > (v = fcntl(ttyfd, F_GETFL, 0))) close(ttyfd), ttyfd = -1, exit(9); if (0 > fcntl(ttyfd, F_SETFL, v | O_NONBLOCK)) close(ttyfd), ttyfd = -1, exit(10); if (0 > tcflush(ttyfd, TCIFLUSH)) close(ttyfd), ttyfd = -1, exit(11); clock_gettime(CLOCK_MONOTONIC, &start_time); start = start_time.tv_sec * 1000 + start_time.tv_nsec / 1000000; INIT_LIST_HEAD(&pl.list); pthread_cond_init(&cPoolEmpty, NULL); pthread_create(&tEmit, NULL, EmitThread, 0); for (;;) { FD_ZERO(&rset); FD_SET(ttyfd, &rset); maxfd = 0; if (maxfd < ttyfd) maxfd = ttyfd; memset(&tv, 0, sizeof(tv)); tv.tv_sec = SELECT_EXPIRY_NINISECONDS / 1000; tv.tv_usec = (SELECT_EXPIRY_NINISECONDS % 1000) * 1000; //res = select(maxfd + 1, &rset, 0, 0, &tv); res = select(maxfd + 1, &rset, 0, 0, 0); if (0 > res) close(ttyfd), ttyfd = -1, exit(12); if (0 == res) continue; if (FD_ISSET(ttyfd, &rset)) { clock_gettime(CLOCK_MONOTONIC, &now_time); now = now_time.tv_sec * 1000 + now_time.tv_nsec / 1000000; res = read(ttyfd, (void *)line, sizeof(line)); if (0 >= res) close(ttyfd), ttyfd = -1, exit(13); for (i = 0; i < res; i++) { onUartChar(line[i]); } if (now - start >= SELECT_EXPIRY_NINISECONDS) { } } } tcsetattr(ttyfd, TCSANOW, &save); close(ttyfd), ttyfd = -1; sleep(1); ioctl(uinputfd, UI_DEV_DESTROY); close(uinputfd), uinputfd = -1; return 0; }
- list.h
-
#ifndef __LIST_H #define __LIST_H /* This file is from Linux Kernel (include/linux/list.h) * and modified by simply removing hardware prefetching of list items. * Here by copyright, credits attributed to wherever they belong. * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) */ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *neu, struct list_head *prev, struct list_head *next) { next->prev = neu; neu->next = next; neu->prev = prev; prev->next = neu; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *neu, struct list_head *head) { __list_add(neu, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *neu, struct list_head *head) { __list_add(neu, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); //entry->next = (void *) 0; //entry->prev = (void *) 0; entry->next = 0; entry->prev = 0; } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif