2010年4月11日星期日

设计多线程安全库

1. 为什么要多线程?
    多线程可以提高系统的性能。更方便实现某些程序模型。

2. posix中的一些线程安全函数如下
        asctime_r, ctime_r, getgrgid_r,getgrnam_r, getpwnam_r,
getpwuid_r, gmtime_r, localtime_r, rand_r, readdir_r, strtok_r

3. 线程安全和可重入例程的特点
线程安全例程是指这个例程即使被多个线程同时调用也不会产生错误的结果。
通常,可以通过一下三种方法来保证线程安全:

3.1 设计成可重入例程
只使用参数和堆栈的例程。   
void test(int *buf) {
           int in_buf[20];
           buf[0] = in_buf[0];
          ....
}
3.2 使用线程局部的数据
使用thread specific data或者Thread local Storage技术的函数
3.3 利用锁技术
spinlock, mutex_lock , ...

4. 非线程安全函数的例子
4.1  libc 中的ctime
返回了全局的静态分配的_tmbuf
struct tm _tmbuf;

/* Return the `struct tm' representation of *T in local time.  */
struct tm *
localtime (t)
     const time_t *t;
{
  return __tz_convert (t, 1, &_tmbuf);
}


2010年4月10日星期六

使用qemu建立简单的ceph分布式文件系统测试环境

1. 下载代码并编译
git clone git://ceph.newdream.net/git/ceph.git
git clone git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git

2. 配置服务端环境并启动服务
2.1 添加use_xattr
在/etc/fstab中,找到服务端所在文件系统的位置,添加use_xattr选项。比如
UUID=c0fb46f4-6b8d-41a3-b026-5850b9f51865 / ext3
relatime,user_xattr,errors=remount-ro 0 1
重启系统

2.2 建立文件夹
mkdir -p dev/osd0
mkdir out
mkdir log

2.3 启动ceph服务, ip地址可以根据自己的环境选择
./vstart.sh -n -d -m 192.168.0.100

3. 测试服务端配置
./csyn --syn makedirs 2 2 2
./csyn --syn walk
执行后,应该可以看到很多文件夹和文件

4. 编译linux客户端
4.1 配置
make menuconfig , 在文件系统中选择ceph

5. 启动qemu 加载ceph文件系统
mount -t ceph 192.168.0.100:/ /mnt/ceph
touch abc

6. 验证
./csyn --syn walk
应该可以看到刚刚建立的文件abc

2009年12月31日星期四

使用iwconfig 配置无线网卡

操作步骤如下:
1. 启动无线网卡
 ifconfig wlan0 on
2.  扫描无线接入点
iwlist wlan0 scanning
3. 连接接入点
iwconfig wlan0 essid   YOUR-SERVICE-NAME
4. 配置网络
例如
ifconfig wlan0 192.168.xxx.xxx netmask 255.255.255.0  up

5. 测试
例如
ping 192.168.1.1

2009年12月14日星期一

使用bootchart-lite监视linux启动和运行状态

使用bootchart可以方便监视linux的启动和运行时的状态,并能将这些状态信息以图形方式表示,以图像方式输出。
但鉴于bootchart的特殊实现方式,它不太适合嵌入式系统。
在嵌入式系统中,可以使用精简化的bootchart--bootchart-lite,替代bootchart。

1. bootchart-lite 源码下载
http://code.google.com/p/bootchart-lite/

2. 编译
CC=arm-linux-gcc ./configure
make
在src目录下面会生成bootchart-lite可执行文件

bootchart-lite 默认配置是把log文件存放在/etc/bootchart-lite/目录下,
使用之前要先建立这个目录。
3. 配置启动参数,让linux启动后,先启动bootchart-lite
init=bootchart-lite

4. 启动linux

5. 收集log文件,渲染图像
bootchart-lite会生成如下3个log文件:
proc_diskstats.log 
proc_ps.log
proc_stat.log

把这3个文件取出后,在pc上运行如下命令:
tar czf bootchart.tgz *.log
bootchart -f png bootchart.tgz

在log所在目录下,会生成一个bootchart.png文件,打开看看你的系统状态吧。。。。

当然,pc上别忘记装bootchart工具。


2009年12月8日星期二

Linux Framebuffer编程简介

linux下,framebuffer设备文件名通常是/dev/fb0,1,2等。
控制framebuffer设备的一般步骤如下:
1) 打开设备,映射framebuffer
2)依照硬件要求,准备好数据
3)把数据复制到framebuffer

例子程序如下:

1)打开设备,映射framebuffer
static void *fbbuf;
int openfb(char *devname)
{
    int fd;
    fd = open(devname, O_RDWR);
    if (ioctl(fd, FBIOGET_VSCREENINFO, &fbvar) < 0)
        return -1;
    bpp = fbvar.bits_per_pixel;
    screen_size = fbvar.xres * fbvar.yres * bpp / 8;
    fbbuf = mmap(0, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    return fd;
}

2)数据准备,假设lcd控制器被初始化为565,16bit格式的
static inline int  make_pixel(unsigned int a, unsigned int r, unsigned int g, unsigned int b)
{
    return (unsigned int)(((r>>3)<<11)|((g>>2)<<5|(b>>3)));
}

3) 把想要显示的数据复制到framebuffer,假设把framebuffer填充成一种颜色
static void fill_pixel(unsigned int pixel, int x0, int y0, int w, int h)
{
    int i, j;
    unsigned short *pbuf = (unsigned short *)fbbuf;
    for (i = y0; i < h; i ++) {
        for (j = x0; j < w; j ++) {
            pbuf[i * screen_width + j] = pixel;
        }
    }
}

2009年11月25日星期三

在nanox中使用cairo来渲染字体

nanox的字体处理功能用起来不是很方便,而cairo有比较强大的字体渲染和画图功能,因此这次尝试将两者结合。

将两者结合时,唯一需要注意的问题是像素的格式区别:
nanox的各颜色通道顺序是: RGBA R是低地址
cairo的顺序是:BGRA B是低地址

示例代码如下:
使用时,先调用prepare函数,创建cairo的surface,然后调用render函数,获取渲染后的图像,图像的地址
通过buf指针传回.这个buf可以通过nanox的GrArea直接显示,比如:
GrArea (win_id, gc_id, 0, 0, width, height, buf_from_cairo, MWPF_RGB);


static cairo_surface_t *prepare_text(int width, int height)
{
cairo_surface_t * surface;
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
fprintf(stderr, "prepare text finished\n");
return surface;
}

static void render_text(cairo_surface_t *surface, unsigned char **buf,
unsigned int *width, unsigned int *height)
{
unsigned char *databuf;
unsigned int dw, dh , ds;
unsigned char *pixbuf;
unsigned int i, j;
cairo_t *cr = cairo_create(surface);
cairo_select_font_face(cr, "Sazanami Gothic",
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 30.0);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_move_to(cr, 0.0, 35.0);
cairo_show_text(cr, "R u 学生.");
cairo_move_to(cr, 0.0, 0.0);
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
cairo_line_to(cr, 100.0, 15.0);
cairo_arc(cr, 200, 30, 15, 0.0, 2 * 3.1415926);
cairo_stroke(cr);
cairo_destroy(cr);

databuf = cairo_image_surface_get_data(surface);
if (!databuf) {
fprintf(stderr, "get cairo image data failed\n");
return;
}

dw = cairo_image_surface_get_width(surface);
dh = cairo_image_surface_get_height(surface);
ds = cairo_image_surface_get_stride(surface);

fprintf(stderr, " w: %d, h: %d, s: %d\n", dw, dh ,ds);
pixbuf = (unsigned char *)malloc(dh * ds);

/* Name : Low High */
/* Cairo: B G R A */ /* src */
/* Nanox: R G B A */ /* dst */
/* only for little endian ? */
for (i = 0; i < dh; i++) {
unsigned char *row = databuf + i * ds;
unsigned char *dst = pixbuf + i * ds;

for (j = 0; j < ds; j += 4) {
unsigned char *data = &row[j];
unsigned char *b = &dst[j];
unsigned int pixel;
/* wait for optimization */
memcpy(&pixel, data, sizeof(unsigned int));

b[0] = (pixel & 0xff0000) >> 16;
b[1] = (pixel & 0x00ff00) >> 8;
b[2] = (pixel & 0x0000ff) >> 0;
b[3] = 0;
}
}
fprintf(stderr, " render text finished\n");
#if 0
cairo_surface_write_to_png(surface, "hello.png");

2009年10月13日星期二

估计yaffs2内存使用情况

yaffs2主要使用内存的地方是yaffs_object和yaffs_tnode,下面的方法大体上可以估计出使用的
内存数量,但由于yaffs2的内存是根据系统运行情况,动态变化的,实际情况会有些出路。

计算方法如下:
1. yaffs_Objectszh占用 内存情况
   每个文件,目录,符号连接都是一个object,每个object大概用了120个字节。
  所以假设有1000个文件,那么object占用ram的大小是1000 * 120 => 120Kbytes

2. yaffs_Tnode 占用内存情况
  首先计算 需要用多少bit数来表示整个nand:
  bitnum =  log2(nand 有的page数目)
  然后在此基础上加1,yaffs内部表示时候需要多一个bit。
  如果如上的bitnum不是偶数,加1。
  最后内存使用情况是bitnum * pagenum / 8 字节

 例如:nand有65536个页面
          bitnum = log2(65536)  + 1 = 16 + 1 = 17
         向上去偶数,得到bitnum = 18
          最后,表示整个nand的tnode用的内存是:
         18 * 65536 / 8 = 147456 字节