2023年1月1日 星期日
Table Of Content for tag "Linux - kernel"
Linux Kernel(1)- Linux Module簡介
Linux Modules(1.1)module parameters
Linux Kernel(2)- register char device
Linux Kernel(2.1)- MAJRO NUMBER RESERVED FOR DYNAMIC ASSIGNMENT
Linux Kernel(3)- procfs
Linux Kernel(3.1)- procfs之vector方式寫入
Linux Kernel(3.2)- procfs之symlink與mkdir
Linux Kernel(4)- seq_file
Linux Kernel(4.1)- seq_file之範例(fp/proc/devices.c)
Linux Kernel(4.2)- seq_file之single page
Linux Kernel(5)- ioctl
Linux Kernel(6)- miscdev
Linux Kernel(7)- timing
Linux Kernel(7.1)- timer
Linux Modules(7.2)- tasklet
Linux Modules(7.3)- work queue
Linux Kernel(8)- Notification
Linux Kernel(8.1)- Notifier機制剖析
Linux Kernel(9)- Kthread
Linux Kernel(10)- MTD/Memory Technology Device
Linux Kernel(10.1)- drivers/mtd/devices/mtdram.c
Linux Kernel(10.2)- mtd partitions
Linux Kernel(10.3)- Command line partition table parsing
Linux Kernel(10.3.1)- Command line partition table parsing for Kernel 4.19
Linux Kernel(11)- sysfs and device node
Linux Kernel(11.1)- sysfs and hotplug
Linux Kernel(11.2)- mdev.conf
Linux Kernel(12)- netfilter
Linux Kernel(12.1)- netfilter機制之初探
Linux Kernel(13)- syscall
Linux Kernel(14)- Kernel Synchronization
Linux Modules(14.1)- Read Copy Update
Linux Kernel(15)- Platform Devices
Linux Kernel(15.1)- platform_driver_register()之如何调用driver.probe()
Linux Kernel(15.2)- platform_device_register()之如何调用driver.probe()
Linux Kernel(15.3)- The Linux usage model for device tree data
Linux Kernel(16.1)- Network Device Driver, simple snull
Linux Kernel(17)- Device Tree
Linux Kernel(17.1)- Basic Device Tree syntax
Linux Kernel(17.2)- Common Device Tree API
Linux Kernel(18)- Virtual File System
Linux Kernel(18.1)- My First Filesystem
Linux Kernel(18.2)- SysCall mount
Linux Kernel(19)- General Purpose Input/Output
Linux Kernel(19.1)- /sys/class/gpio usage
Linux Kernel(20)- Input device
Linux Kernel(20.1)- Input device user program
Linux Kernel(20.2)- uinput module
Linux Kernel(20.3)- Creating an input device driver
Linux Kernel(21)- ID Allocation
Linux Kernel(21.1)- ID Allocation
Linux Kernel(21.2)- radix tree API
Linux Kernel(21.3)- radix tree implementation
Linux Kernel(22)- Linux Socket
Linux Kernel(22.1)- My Socket Domain and Protocol
Linux Kernel(23)- SKB
Linux Kernel(24)- Multimedia Card
Linux Kernel(24.1)- fdisk Multimedia Card
Linux Kernel(25)- USB(Universal Serial Bus)
Linux Kernel(25.1)- Gadget Configfs
2019年8月18日 星期日
Linux Kernel(17.1)- Basic Device Tree syntax
這篇會介紹一下Device Tree的基本資料型態,並透過觀察/sys/firmware/devicetree/讓你更貼近一下DT的資料結構,下面範例是在vexpress-v2p-ca9.dts中include "brook.dtsi",然後在"brook.dtsi"撰寫DT的基本語法。DT的每個node,可包含零個以上的properties或child node。
brook@vista:~/qemu/linux-arm$ vim arch/arm/boot/dts/vexpress-v2p-ca9.dts #include "vexpress-v2m.dtsi" #include "brook.dtsi" /* add this line */ brook@vista:~/qemu/linux-arm$ vim arch/arm/boot/dts/brook.dtsi / { node1 { a-string-property = "A string"; a-string-list-property = "first string", "second string"; // hex is implied in byte arrays. no '0x' prefix is required a-byte-data-property = [01 23 34 56]; child-node1 { first-child-property; second-child-property = <1>; a-string-property = "Hello, world"; }; child-node2 { }; }; node2 { an-empty-property; a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ //[@ brook@vista:~/qemu/linux-arm$ export ARCH=arm brook@vista:~/qemu/linux-arm$ export CROSS_COMPILE=arm-linux-gnueabihf- brook@vista:~/qemu/linux-arm$ export PATH=/opt/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin:$PATH brook@vista:~/qemu/linux-arm$ make dtbs], // is a simple ascii string and can be up to 31 characters in length. child-node@1 { }; child-node@2 { }; }; };
properties的value可以是empty或是以下資料型態:
- Text strings (null terminated) are represented with double quotes: string-property = "a string";
- 'Cells' are 32 bit unsigned integers delimited by angle brackets: cell-property = <0xbeef 123 0xabcd1234>;
- Binary data is delimited with square brackets: binary-property = [0x01 0x23 0x45 0x67];
- Data of differing representations can be concatenated together using a comma: mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
- Commas are also used to create lists of strings: string-list = "red fish", "blue fish";
brook@vista:~/qemu/linux-arm# cd .. brook@vista:~/qemu$ qemu-system-arm -M vexpress-a9 -m 512M -kernel ./linux-arm/arch/arm/boot/zImage -dtb ./linux-arm/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -initrd ./initrd-arm.img -nographic -append "console=ttyAMA0" ----- boot to VM ----- Please press Enter to activate this console. / # ls /sys/firmware/ devicetree fdt / # ls /sys/firmware/devicetree/ base / # ls /sys/firmware/devicetree/base/ #根目錄(/sys/firmware/devicetree/base/) 多了node1與node2 / # ls /sys/firmware/devicetree/base/ #address-cells model #size-cells name aliases node1 arm,hbi node2 arm,vexpress,site pmu cache-controller@1e00a000 reserved-memory chosen scu@1e000000 clcd@10020000 smb@4000000 compatible timer@100e4000 cpus timer@1e000600 dcc virtio_mmio@10013000 hsb@e0000000 virtio_mmio@10013200 interrupt-controller@1e001000 virtio_mmio@10013400 interrupt-parent virtio_mmio@10013600 memory-controller@100e0000 watchdog@100e5000 memory-controller@100e1000 watchdog@1e000620 memory@60000000 / # find /sys/firmware/devicetree/base/node1 /sys/firmware/devicetree/base/node1 /sys/firmware/devicetree/base/node1/child-node2 /sys/firmware/devicetree/base/node1/child-node2/name /sys/firmware/devicetree/base/node1/a-string-property /sys/firmware/devicetree/base/node1/a-string-list-property /sys/firmware/devicetree/base/node1/a-byte-data-property /sys/firmware/devicetree/base/node1/name /sys/firmware/devicetree/base/node1/child-node1 /sys/firmware/devicetree/base/node1/child-node1/first-child-property /sys/firmware/devicetree/base/node1/child-node1/second-child-property /sys/firmware/devicetree/base/node1/child-node1/a-string-property /sys/firmware/devicetree/base/node1/child-node1/name / # find /sys/firmware/devicetree/base/node2 /sys/firmware/devicetree/base/node2 /sys/firmware/devicetree/base/node2/child-node@1 /sys/firmware/devicetree/base/node2/child-node@1/name /sys/firmware/devicetree/base/node2/child-node@2 /sys/firmware/devicetree/base/node2/child-node@2/name /sys/firmware/devicetree/base/node2/a-cell-property /sys/firmware/devicetree/base/node2/name /sys/firmware/devicetree/base/node2/an-empty-property / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/a-string-property 41 20 73 74 72 69 6E 67 A string 00 / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/a-string-list-property 66 69 72 73 74 20 73 74 first st 72 69 6E 67 00 73 65 63 ringsec 6F 6E 64 20 73 74 72 69 ond stri 6E 67 00 ng strings lists中的element是"0"分隔 / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/a-byte-data-property 01 23 34 56 #4V byte-data如其名,每個值大小就是一個byte / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/name 6E 6F 64 65 31 00 node1 / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/child-node1/first-child-property empty / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/child-node1/second-child-property 00 00 00 01 / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node1/child-node1/a-string-property 48 65 6C 6C 6F 2C 20 77 Hello, w 6F 72 6C 64 00 orld / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node2/a-cell-property 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 cell每個value大小為32byte / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node2/child-node@1/name 63 68 69 6C 64 2D 6E 6F child-no 64 65 00 de / # hexdump -e '8/1 "%02X ""\t"" "' -e '8/1 "%c""\n"' /sys/firmware/devicetree/base/node2/child-node@2/name 63 68 69 6C 64 2D 6E 6F child-no 64 65 00 de
-
參考資料:
- https://elinux.org/Device_Tree_Usage, Device Tree Usage
- https://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf, device tree dumies
- https://blog.csdn.net/RadianceBlau/article/details/70800076, Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)
2018年3月17日 星期六
An Sample Code for threads control - A Wrap for service/thread start/stop/periodical run
multi-thread programming設計很常見, 寫法上與功能上也都很相似, 最基本的幾個操作就是, create/start/stop/periodical run/destroy等等. 最好還能monitor這些thread狀況, 比如被執行幾次, 執行時間多久, 是否有dead lock等等, 於是就寫了這個pattern, 提供這類功能.
service-reg.h
#ifndef SERVICE_REG_H #define SERVICE_REG_H #include <sys/time.h> typedef void *(*srv_fp) (void *); char * srv_dump(char *buf, int sz); int _srv_reg(char *srv_name, srv_fp fp, char *fp_name, void *srv_data); #define srv_reg(srv_name, fp, srv_data) _srv_reg(srv_name, fp, #fp, srv_data) int srv_start(char *srv_name); // run forever without any delay int srv_stop(char *srv_name); int srv_unreg(char *srv_name); int srv_start_periodical(char *srv_name, unsigned long sec, unsigned long nsec); // run forever with delay #define SRV_NO_MEM -1 #endif
service-reg.c
#include <pthread.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <ctype.h> #include <time.h> #include <sys/time.h> #include <sys/timerfd.h> #include <stdint.h> #include <unistd.h> #include "service-reg.h" #include "lookup_table.h" #define SEC2NSEC 1000000000.0 struct srv_info { void *srv_data; char *srv_name; srv_fp fp; int in_fp; char *fp_name; unsigned run_cnt; pthread_t thread_id; /* ID returned by pthread_create() */ pthread_cond_t cond; pthread_mutex_t mutex; struct srv_info *next; volatile int running; /* 1 for running, 0 for stop */ struct timespec active_time; struct timespec last_enter; struct timespec last_exit; int tm_fd; /* used to delay */ }; struct srv_tab { pthread_mutex_t mutex; struct srv_info *list; unsigned int num_srv; } srv_tab = { .mutex = PTHREAD_MUTEX_INITIALIZER, .list = NULL, .num_srv = 0, }; static void _srv_update_active_time(struct srv_info *s) { clock_gettime(CLOCK_MONOTONIC, &(s->last_exit)); s->active_time.tv_sec += s->last_exit.tv_sec - s->last_enter.tv_sec; if (s->last_exit.tv_nsec > s->last_enter.tv_nsec) { s->active_time.tv_nsec += s->last_exit.tv_nsec - s->last_enter.tv_nsec; } else { s->active_time.tv_sec--; s->active_time.tv_nsec += SEC2NSEC + s->last_exit.tv_nsec - s->last_enter.tv_nsec; } if (s->active_time.tv_nsec >= SEC2NSEC) { s->active_time.tv_nsec -= SEC2NSEC; s->active_time.tv_sec++; } } static void *_srv_wrap(void *v) { struct srv_info *s = (struct srv_info *) v; while (1) { recheck: if (s->running == 0) { stoprun: pthread_cond_wait(&(s->cond), &(s->mutex)); goto recheck; } /* if timer is enabled, than wait */ again: if (s->tm_fd != -1) { uint64_t exp; ssize_t sz; sz = read(s->tm_fd, &exp, sizeof(exp)); if (sz != sizeof(exp)) { printf("timerfd_settime failed: s->tm_fd:%d, errno:%d/%s\n", s->tm_fd, errno, strerror(errno)); if (errno == EINTR) { goto again; } } if (s->running == 0) { goto stoprun; } } clock_gettime(CLOCK_MONOTONIC, &(s->last_enter)); s->in_fp = 1; s->fp(s->srv_data); s->in_fp = 0; _srv_update_active_time(s); s->run_cnt++; } return NULL; } int srv_init(void) { return 0; } char * srv_dump(char *buf, int sz) { struct srv_info *s; char *p = buf; int i = 0; struct timespec cur_clk; struct itimerspec cur_timer; clock_gettime(CLOCK_MONOTONIC, &cur_clk); if (buf == NULL) { return NULL; } memset(buf, 0, sz); pthread_mutex_lock(&(srv_tab.mutex)); s = srv_tab.list; p += snprintf(p, sz - (buf - p), "cur-clk: %f\n", cur_clk.tv_sec + cur_clk.tv_nsec/SEC2NSEC); p += snprintf(p, sz - (buf - p), "id srv_name running/in_fp\t\tfp/fname/dp\n"); p += snprintf(p, sz - (buf - p), "\t\t\trun-cnt/run-time\tenter-clk/leave-clk\n"); p += snprintf(p, sz - (buf - p), "\t\t\ttm_fd/next_expir/perodic\n"); while (s != NULL) { p += snprintf(p, sz - (buf - p), "%-8d%-16s%2d/%-2d\t\t%16p/%s/%-16p\t\t\t\n", i++, s->srv_name, s->running, s->in_fp, s->fp, s->fp_name, s->srv_data); p += snprintf(p, sz - (buf - p), "\t\t %10d/%-12f\t%12f/%-12f\n", s->run_cnt, s->active_time.tv_sec + s->active_time.tv_nsec/SEC2NSEC, s->last_enter.tv_sec + s->last_enter.tv_nsec/SEC2NSEC, s->last_exit.tv_sec + s->last_exit.tv_nsec/SEC2NSEC); if (s->tm_fd != -1) { if (timerfd_gettime(s->tm_fd, &cur_timer) < 0) { printf("timerfd_get failed: errno:%d/%s\n", errno, strerror(errno)); p += snprintf(p, sz - (buf - p), "\t\t %6d\n", s->tm_fd); } else { p += snprintf(p, sz - (buf - p), "\t\t %6d/%f/%-16f\n", s->tm_fd, cur_timer.it_value.tv_sec + cur_timer.it_value.tv_nsec/SEC2NSEC, cur_timer.it_interval.tv_sec + cur_timer.it_interval.tv_nsec/SEC2NSEC); } } s = s->next; } pthread_mutex_unlock(&(srv_tab.mutex)); return buf; } int _srv_reg(char *srv_name, srv_fp fp, char *fp_name, void *srv_data) { struct srv_info *s = (struct srv_info *) malloc(sizeof(struct srv_info)); if (s == NULL) { return SRV_NO_MEM; } memset(s, 0, sizeof(struct srv_info)); s->fp = fp; s->srv_data = srv_data; s->srv_name = strdup(srv_name); s->fp_name = strdup(fp_name); pthread_cond_init(&s->cond, NULL); pthread_mutex_init(&s->mutex, NULL); s->tm_fd = -1; if (!s->srv_name) { free(s); return SRV_NO_MEM; } /* insert into tab */ pthread_mutex_lock(&(srv_tab.mutex)); s->next = srv_tab.list; srv_tab.list = s; srv_tab.num_srv++; pthread_mutex_unlock(&(srv_tab.mutex)); /* create the thread */ pthread_create(&s->thread_id, NULL , _srv_wrap, s); return 0; } static int _srv_update_timer(struct srv_info *s, unsigned long sec, unsigned long nsec) { struct timespec now_tm; struct itimerspec new_tm; if (s->tm_fd < 0) { s->tm_fd = timerfd_create(CLOCK_MONOTONIC, 0); if (s->tm_fd < 0) { printf("timerfd_create failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } } if (clock_gettime(CLOCK_MONOTONIC, &now_tm) == -1) { printf("timerfd_create failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } new_tm.it_value.tv_sec = now_tm.tv_sec + sec; new_tm.it_value.tv_nsec = now_tm.tv_nsec + nsec; new_tm.it_interval.tv_sec = sec; new_tm.it_interval.tv_nsec = nsec; if (timerfd_settime(s->tm_fd, TFD_TIMER_ABSTIME, &new_tm, NULL) < 0) { printf("timerfd_settime failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } return 0; } inline static int _srv_name_equal(struct srv_info *s, char *srv_name) { return strlen(s->srv_name) == strlen(srv_name) && !strcmp(s->srv_name, srv_name); } static int _srv_set_running(char *srv_name, int running, unsigned long sec, unsigned long nsec) { struct srv_info *s; int ret = 0; pthread_mutex_lock(&(srv_tab.mutex)); s = srv_tab.list; while (s != NULL) { if (_srv_name_equal(s, srv_name)) { s->running = running; if (sec || nsec) { ret = _srv_update_timer(s, sec, nsec); } else { /* reset timer to zero */ _srv_update_timer(s, 0, 0); /* clear timer */ close(s->tm_fd); s->tm_fd = -1; } pthread_cond_signal(&s->cond); pthread_mutex_unlock(&(srv_tab.mutex)); return ret; } s = s->next; } pthread_mutex_unlock(&(srv_tab.mutex)); return -1; } int srv_start(char *srv_name) { return _srv_set_running(srv_name, 1 /* running */, 0 /* delay.sec */, 0 /* delay.nsec */); } int srv_stop(char *srv_name) { return _srv_set_running(srv_name, 0 /* running */, 0 /* delay.sec */, 0 /* delay.nsec */); } static int _srv_free(struct srv_info *s) { int ret; s->running = 0; /* cancel the thread */ ret = pthread_cancel(s->thread_id); if (ret != 0) { printf("pthread_cancel failed: %d/%d\n", ret, errno); /* FIXME */ } ret = pthread_join(s->thread_id, NULL); if (ret != 0) { printf("pthread_join failed: %d/%d\n", ret, errno); /* FIXME */ } /* free resouce */ pthread_cond_destroy(&(s->cond)); pthread_mutex_destroy(&(s->mutex)); free(s->srv_name); free(s->fp_name); if (s->tm_fd != -1) { close(s->tm_fd); } free(s); return ret; } int srv_unreg(char *srv_name) { struct srv_info **s, *sn = NULL; int ret; s = &(srv_tab.list); pthread_mutex_lock(&(srv_tab.mutex)); while ((*s) != NULL) { if (_srv_name_equal(*s, srv_name)) { sn = *s; *s = (*s)->next; srv_tab.num_srv--; break; } s = &((*s)->next); } pthread_mutex_unlock(&(srv_tab.mutex)); if (sn) { ret = _srv_free(sn); } return 0; } int srv_start_periodical(char *srv_name, unsigned long sec, unsigned long nsec) { return _srv_set_running(srv_name, 1 /* running */, sec /* delay.sec */, nsec /* delay.nsec */); }
main.c (test program)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <stdarg.h> #include "service-reg.h" int pr(const char *fmt, ...) { va_list ap; int ret; struct timespec cur_clk; clock_gettime(CLOCK_MONOTONIC, &cur_clk); printf("***CLK: %f\n", cur_clk.tv_sec + cur_clk.tv_nsec/1000000000.0); va_start(ap, fmt); ret = vprintf(fmt, ap); va_end(ap); return ret; } void *sms_service(void *v) { int *i = (int *) v; pr(" ->hello, %p/%d, srv_start_periodical %d\n", v, (*i)++, 2); pr(" ->%d\n", srv_start_periodical("brook", 2, 0)); } int main(int argc, char *argv[]) { int i = 0, data = 0, ret; char name[] = "brook", buf[1024]; pr("srv_reg %s\n", name); srv_reg(name, sms_service, (void*)&data); pr("srv_start %s\n", name); srv_start(name); pr("sleep 3\n"); sleep(3); sleep(3); pr("srv_stop %s\n", name); srv_stop(name); pr("srv_start_periodical %s with %dsec\n", name, 1); srv_start_periodical(name, 1, 0); pr("srv_dump %s\n", name); pr("%s\n", srv_dump(buf, sizeof(buf))); pr("sleep 2\n"); sleep(2); pr("srv_unreg %s\n", name); srv_unreg(name); pr("over\n"); return 0; }
執行結果
brook@vista:~$ ./service-reg ***CLK: 7914669.498393 srv_reg brook ***CLK: 7914669.498469 srv_start brook ***CLK: 7914669.498481 sleep 3 ***CLK: 7914669.498531 ->hello, 0x7ffc24e80df8/0, srv_start_periodical 2 ***CLK: 7914669.498541 ->0 ***CLK: 7914671.498595 ->hello, 0x7ffc24e80df8/1, srv_start_periodical 2 ***CLK: 7914671.498647 ->0 ***CLK: 7914672.498576 srv_stop brook ***CLK: 7914672.498599 srv_start_periodical brook with 1sec ***CLK: 7914672.498606 srv_dump brook ***CLK: 7914672.498621 ->hello, 0x7ffc24e80df8/2, srv_start_periodical 2 ***CLK: 7914672.498662 ->0 ***CLK: 7914672.498625 cur-clk: 7914672.498611 id srv_name running/in_fp fp/fname/dp run-cnt/run-time enter-clk/leave-clk tm_fd/next_expir/perodic 0 brook 1/0 0x40106f/sms_service/0x7ffc24e80df8 2/0.000082 7914671.498594/7914671.498656 3/0.999982/1.000000 ***CLK: 7914672.498680 sleep 2 ***CLK: 7914674.498698 ->hello, 0x7ffc24e80df8/3, srv_start_periodical 2 ***CLK: 7914674.498730 ->0 ***CLK: 7914674.498742 srv_unreg brook ***CLK: 7914674.498997 over
2016年10月9日 星期日
Install Node.js on Openembedded
基本上Node.js在Openembedded上的recipes都已經寫好了,只要clone下來,並且加入IMAGE_INSTALL列表即可
brook@vista:~/projects/poky$ git clone https://github.com/imyller/meta-nodejs.git Cloning into 'meta-nodejs'... remote: Counting objects: 1575, done. remote: Compressing objects: 100% (14/14), done. remote: Total 1575 (delta 9), reused 0 (delta 0), pack-reused 1561 Receiving objects: 100% (1575/1575), 241.91 KiB | 368.00 KiB/s, done. Resolving deltas: 100% (846/846), done. Checking connectivity... done. brook@vista:~/projects/poky$ . oe-init-build-env You had no conf/local.conf file. This configuration file has therefore been created for you with some default values. You may wish to edit it to, for example, select a different MACHINE (target hardware). See conf/local.conf for more information as common configuration options are commented. You had no conf/bblayers.conf file. This configuration file has therefore been created for you with some default values. To add additional metadata layers into your configuration please add entries to conf/bblayers.conf. The Yocto Project has extensive documentation about OE including a reference manual which can be found at: http://yoctoproject.org/documentation For more information about OpenEmbedded see their website: http://www.openembedded.org/ ### Shell environment set up for builds. ### You can now run 'bitbake <target>' Common targets are: core-image-minimal core-image-sato meta-toolchain meta-ide-support You can also run generated qemu images with a command like 'runqemu qemux86' brook@vista:~/projects/poky/build$ vim conf/bblayers.conf ...下段說明 brook@vista:~/projects/poky/build$ vim conf/local.conf ...下段說明 brook@vista:~/projects/poky/build$ bitbake core-image-minimal WARNING: Host distribution "Ubuntu-16.04" has not been validated with this version of the build system; you may possibly experience unexpected failures. It is recommended that you use a tested distribution. Parsing recipes: 100% |#############################################################################################| Time: 00:00:28 Parsing of 876 .bb files complete (0 cached, 876 parsed). 1316 targets, 49 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Build Configuration: BB_VERSION = "1.30.0" BUILD_SYS = "x86_64-linux" NATIVELSBSTRING = "Ubuntu-16.04" TARGET_SYS = "i586-poky-linux" MACHINE = "qemux86" DISTRO = "poky" DISTRO_VERSION = "2.1.1" TUNE_FEATURES = "m32 i586" TARGET_FPU = "" meta meta-poky meta-yocto-bsp = "krogoth:8c69f7d56cbd496aa01ba0738675a170826a536b" meta-nodejs = "master:848b0defe8eba6e7ffa97b66e4316c17c92be9d4" ... brook@vista:~/projects/poky/build$ ./tmp/sysroots/x86_64-linux/usr/bin/qemu-system-i386 -nographic -kernel ./tmp/deploy/images/qemux86/bzImage-qemux86.bin -cpu qemu32 -drive file=./tmp/deploy/images/qemux86/core-image-minimal-qemux86.ext4,if=virtio,format=raw -show-cursor -usb -usbdevice tablet -vga vmware -no-reboot -m 256 -append "vga=0 uvesafb.mode_option=640x480-32 root=/dev/vda rw mem=256M ip=192.168.7.2::192.168.7.1:255.255.255.0 oprofile.timer=1 rootfstype=ext4 " Poky (Yocto Project Reference Distro) 2.1.1 qemux86 /dev/ttyS0 qemux86 login: root root@qemux86:~# uname -a Linux qemux86 4.4.11-yocto-standard #1 SMP PREEMPT Sun Oct 9 19:29:24 CST 2016 i686 GNU/Linux root@qemux86:~# echo 'console.log("hello world");' > node.js root@qemux86:~# node node.js hello world
conf/bblayers.conf修改的內容
BBLAYERS ?= " \ /home/brook/projects/poky/meta \ /home/brook/projects/poky/meta-poky \ /home/brook/projects/poky/meta-yocto-bsp \ ${TOPDIR}/../meta-nodejs \ "
conf/local.conf修改的內容
# This sets the default machine to be qemux86 if no other machine is selected: MACHINE ??= "qemux86" CORE_IMAGE_EXTRA_INSTALL += "nodejs"
-
參考資料:
- meta-nodejs, Node.js的openembedded recipes。
- JavaScript for IoT: Blinking LED on Raspberry Pi with Node.js , Node.js的demo影片。
- 「Node.js & IoT: Zero to One」 是一本 Node.js 的入門電子書,內容定位為基礎教學,目標是介紹 Node.js 以及 Node.js + IoT 相關技術主題,每個主題都從基本觀念(Zero)開始,介紹到能撰寫簡單的程式為止(One)。不過目前只有介紹JS的基本語法。
- Addons。教你如何擴充JS,用C/C++寫一個Node.js module。
標籤:
Node.js,
OpenEmbedded
2009年12月27日 星期日
Linux Modules(7.2)- tasklet
Tasklet和timer類似(基本上都是運作在Softirqs上面),但是不同於timer會在特定時間執行,tasklet會在下一次interrupt來臨時執行。Tasklet有兩種implement,分別為TASKLET_SOFTIRQ和HI_SOFTIRQ,這兩種的差別在於HI_SOFTIRQ筆TASKLET_SOFTIRQ早執行。另外Tasklet只在註冊的CPU上面執行,而且註冊的tasklet同一時間只會被某個CPU執行。
您可以dynamically或statically的建立tasklet,
DECLARE_TASKLET(task, func, data);
DECLARE_TASKLET_DISABLED(task, func, data);
tasklet_init(task, func, data);
宣告後,還必須呼叫tasklet_schedule(task)才會被執行,但如果是用
DECLARE_TASKLET_DISABLED()宣告成disabled狀態,那就還必須用tasklet_enable()將其狀態設成enabled才能被執行。您也可以透過tasklet_disabled() disabled某個tasklet。tasklet_kill()可以保證tasklet不會被schedule,如果已經在執行,就會等它執行結束。
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/slab.h> MODULE_LICENSE("GPL"); static void f(unsigned long name); // create tasklet statically static DECLARE_TASKLET(t1, f, (unsigned long)"t1"); static DECLARE_TASKLET_DISABLED(t2, f, (unsigned long)"t2"); static struct tasklet_struct *t3; static void f(unsigned long name) { printk("%s(): on cpu %d\n", (char*)name, smp_processor_id()); } static void f3(unsigned long name) { static u32 c = 0; tasklet_schedule(t3); if (!(c++ % 2000000)) { // 每隔2000000次呼叫就印出訊息 printk("%s(): on cpu %d\n", (char*)name, smp_processor_id()); } } static int __init init_modules(void) { // create tasklet dynamically t3 = kzalloc(sizeof(struct tasklet_struct), GFP_KERNEL); tasklet_init(t3, f3, (unsigned long)"t3"); tasklet_schedule(&t1); tasklet_schedule(&t2); tasklet_schedule(t3); tasklet_enable(&t2); // 沒有enable就不會被啟動 return 0; } static void __exit exit_modules(void) { // remove module就應該要確保tasklet有被移除 tasklet_kill(&t1); tasklet_kill(&t2); tasklet_kill(t3); } module_init(init_modules); module_exit(exit_modules);
Based on Kernel Version:2.6.35
參考資料:
Linux Kernel Development 3rd.
Linux Device Driver 3rd, http://www.makelinux.net/ldd3/chp-7-sect-5.shtml
標籤:
Linux - kernel
Linux Kernel(7.1)- timer
有時候我們希望能在某個時間點執行某些動作,這時候便可以使用timer,在使用timer有些規矩必須被遵守。因為不是user-space來喚起,所以不允許存取user-space,current也就沒有意義。不能休眠,也不准schedule()或者任何有可能休眠的動作都不准。
struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_base *base; #ifdef CONFIG_TIMER_STATS void *start_site; char start_comm[16]; int start_pid; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif };
timer_list必須初始化之後才能使用,您可以選擇init_timer()或TIMER_INITIALIZER(),接著就可以設定expires/callback function/data(參數),並且使用add_timer()將其加入timer中,或者使用del_timer()移除pending中的timer,也可以使用mod_timer()修改或者重新設定timer。
#include <linux/init.h> #include <linux/module.h> #include <linux/timer.h> MODULE_LICENSE("GPL"); struct timer_list brook_timer; static void callback(unsigned long); struct data { int count; }; static struct data data; static void callback(unsigned long data) { struct data *dp = (struct data*) data; printk("%s(): %d\n", __FUNCTION__, dp->count++); mod_timer(&brook_timer, jiffies + 5 * HZ); } static int __init init_modules(void) { init_timer(&brook_timer); brook_timer.expires = jiffies + 5 * HZ; brook_timer.function = &callback; brook_timer.data = (unsigned long) &data; add_timer(&brook_timer); return 0; } static void __exit exit_modules(void) { del_timer(&brook_timer); } module_init(init_modules); module_exit(exit_modules);

kernel timer最短的間隔是1個jiffies,而且會受到硬體中斷,和其他非同步事件的干擾,所以不適合非常精密的應用。
標籤:
Linux - kernel
Linux Kernel(7)- timing
kernel會定期產生timer interrupt,HZ定義每秒產生timer interrupt的次數,定義在linux/param.h,根據平台的不同從50~1200不等。
而jiffies每當發生一次timer interrupt就會遞增一次,jiffies定義於linux/jiffies.h,所以簡單的說,jiffies就等於1/HZ,不管在64bit或32bit上的機器,Linux kernel都使用64位元版的jiffies_64,而jiffies其實是jiffies_64的低32位元版,除了讀取外,我們都不應該直接修改jiffies/jiffies_64。
kernel提供幾組macro來比較時間的先後,time_after()/timer_before()/time_after_eq()/time_before_eq()。
/* * These inlines deal with timer wrapping correctly. You are * strongly encouraged to use them * 1. Because people otherwise forget * 2. Because if the timer wrap changes in future you won't have to * alter your driver code. * * time_after(a,b) returns true if the time a is after time b. * * Do this with "<0" and ">=0" to only test the sign of the result. A * good compiler would generate better code (and a really good compiler * wouldn't care). Gcc is currently neither. */ #define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) #define time_before(a,b) time_after(b,a) #define time_after_eq(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(a) - (long)(b) >= 0)) #define time_before_eq(a,b) time_after_eq(b,a)
另外,kernel中有兩種時間的structure,struct timeval和struct timespec。
#ifndef _STRUCT_TIMESPEC #define _STRUCT_TIMESPEC struct timespec { __kernel_time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif struct timeval { __kernel_time_t tv_sec; /* seconds */ __kernel_suseconds_t tv_usec; /* microseconds */ };早期以timeval為主,後來因為精密度的需求,有了timespec的誕生。kernel也提供了和jiffies的轉換函數。更多的轉換可以參考linux/jiffies.h
unsigned long timespec_to_jiffies(const struct timespec *value); void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value); unsigned long timeval_to_jiffies(const struct timeval *value); void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value);
標籤:
Linux - kernel
訂閱:
文章 (Atom)
熱門文章
-
轉自 http://www.wretch.cc/blog/redsonoma/14021073 基本概念: 1> tty(終端設備的統稱): tty一詞源於Teletypes,或者teletypewriters,原來指的是電傳打字機,是通過串行線用打印機鍵盤通過閱...
-
Work queue提供一個interface,讓使用者輕易的建立kernel thread並且將work綁在這個kernel thread上面,如下圖[1]所示。 由於work queue是建立一個kernel thread來執行,所以是在process context...
-
(V)將介紹file operations中的ioctl。ioctl的prototype為: int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ...
-
這兩天電腦的word忽然都不能存檔,即便是另存新檔也不行,最後都只能放棄修改檔案,即便重新安裝過或者更新成2007也都不能存檔,最後就乖乖的google一下,原來是暫存的資料夾不存在,按照以下方式就可以解決了。 資料來源: word 2003不能存檔問題 編輯機碼的(reg...
-
System Call在HW和user space提供一層抽象層,主要目的有: 為user space提供硬體抽象層。比如,讀取檔案時,不用管檔案所在的媒體類型與檔案儲存類型。 System call能確保系統的安全與穩定。避免user space的無意或惡意的破壞。 ...
-
在kernel中建立thread可以使用kthread_create(),建立一個task,然後在調用wake_up_process(task)讓task真正的運行,如果要kill一個kthread可以使用kthread_stop()。 在kernel中,將kthread_cr...
-
Linux module練習手札I紀錄如何撰寫一個簡單的module,並且編輯它,以及load和unload一個module。 write a module #include <linux/init.h> #include <linux/module.h...
-
幾乎任何使用 TCP,UDP或UNIX-domain socket的動作都可以用nc來達成,常見的功能如。 simple TCP proxies shell-script based HTTP clients and servers network daemon testi...
-
很多人心中都有過一個問題 What is the difference between Platform driver and normal device driver? ,簡單的來說Platform devices就non-discoverable,也就是device本身沒辦法...
-
組成元件 要能正確顯示資料,必須包含資料倉儲(Store),資料欄位的定義(ColumnModel)。 首先我們先定義資料欄位: var cm = new Ext.grid.ColumnModel({ {header: 'Name', dataIndex...