分类: LINUX
2009-07-22 21:12:47
Redhat9安装
分区:手动分区:/swap:内存的1.5倍
/根分区6G左右
/boot
配置引导程序GRUB:添加要引导的操作系统、选择要默认引导的操作系统
网络配置:Redhat和windows在同一网段;Redhat的网关是windows的IP
账号root配置:密码
软件包:X窗口系统、GNOME\KDE、编辑器、服务器配置工具、windows文件服务器、开发工
具、内核开发、管理工具、系统工具
gdb调试
1.l(list) 列出程序清单
2.r(run) 运行程序
3.s(step) 单步运行 step into
4.n(next) 单步运行 step over
5.finish 跳出函数 step out
6.b(breakpoint) 设置断点 格式: b [行号/函数名]
7.b num if i==20 设置断点的触发条件
8.condition 断点号 i==50 改变断点的触发条件
9.info b 查看断点信息
10.clear [行号] 清除断点
11. c (continue) 继续运行程序
12.print 变量/表达式 显示变量或表达式的值
13.display 变量/表达式 每次程序停止运行时都显示变量或表达式的值
交叉编译平台的搭建
开发板运行环境
1.bon part 0 全盘格式化(part后面是零)
2.用sjf烧写vivi 选择好相应的芯片类型 如2410 烧写位置为0;
3.用串口下载kernel
vivi>load flash kernel x-->传送:zImage 下载到flash的root分区 用modern x协议传输
4.用串口下载rootfs:
vivi>load flash root x-->传送:root.cramfs 下载文件系统 用modern x 协议传输
交叉编译工具链的配置
1.tar xjvf arm-linux-tools3.4.1.tar.bz2
解压后里面的arm-linux-xxx等文件可以编译连接出在arm平台下执行的文件
2.环境变量的配置
方法一:export PATH=/usr/local/arm/3.4.1/bin:$PATH
方法二:vi /root/./bash_profile-->添PATH=$PATH:
$HOME/bin:/usr/local/arm/3.4.1/bin
退出vi后 执行source .bash_profile //更新环境变量
NFS服务配置
1.开始-->系统设置-->服务器设置-->NFS服务器-->增加
-->基本:目录:设置可以挂载的目录 如/home/sure;主机:设置可以挂载的IP范围(主
机、虚拟机、开发板在一个网段)基本权限:读写
-->常规:允许来自高于1024的端口的连接
-->用户访问:把远程根用户当作本地根用户
2.配置主机、虚拟机、开发板IP
如:主机:IP: 192.168.220.X netmask: 255.255.255.0
虚拟机linux:ifconfig eth0 192.168.220.XX netmask 255.255.255.0
开发板:ifconfig eth0 192.168.220.XXX netmask 255.255.255.0
挂载
mount -o nolock 192.168.220.XX:/home/sure/ /tmp // 挂载nfs服务
Samba服务器的配置
1.开始-->系统设置-->服务器设置-->Samba服务器-->增加-->首选项:设置好UNIX、
WINDOWS的用户名、口令即可
2.增加-->基本:目录:设置要共享的目录;基本权限:读写;
访问:选择可以访问共享目录的用户(类似一个登录账号)
3.设置虚拟机IP:确定和XP在同一个网段
4.service smb restart
makefile
1.object=*.o ...
exe:$(boject)
gcc -o exe $(object)
$(boject): *.c ... *.h ...// 可以省略*.c ...
gcc -c *c
clean:
rm -rfv *.o
2.object=*.o
CC=gcc
exe:$(object)
$(object):%.o:%.c
$(CC) -c $< -o $@
automake makefile
多个文件:main.c 、 fun.c和fun.h
1、autoscan :生成configure.scan、autoscan.log文件。
2、编辑configure.scan文件,并改名为configure.in:
AC_PREREQ(2.57)
AC_INIT(main,1.0)
AM_INIT_AUTOMAKE(main,1.0)
AC_PROG_CC
AC_OUTPUT(Makefile)
3、aclocal:生成aclocal.m4文件
4、autoconf:autom4te.cache
5、新建Makefile.am文件:(这里比较实用的命令是:r!ls*.c)
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS= main / /要生成的目标文件
main_SOURCES= main.c fun.c / /所有的.c文件
6、automake --add-missing:生成 makefile.in等文件
7、./confgure:将makefile.in文件变为Makefile文件。
8、make 生成目标
添加系统调用
1.添加源代码
将要添加的函数的前面加上sys_;eg.要添加系统调用fn()
则在linux/kernel/sys.c中添加sys_fn()的代码//linux为新内核的文件夹
2.连接新系统调用
打开linux/include/asm-i386/unistd.h文件(此文件包含了系统调用清单,用来为每个系统调用分配一个唯一的系统调用号)
系统调用号的定义格式:#inlcude __NR_name NNN;eg.#denfine __NR_fn 238
3.重新编译内核
以root的身份登录,进入linux,重建内核
1).make menuconfig
//配置内核File systems-->选择ext3文件系统支持-->M:编译成模块;*:添加到kernel
2).make clean //清楚以前编译的中间文件
3).make dep //读取配置文件,创建依赖关系树
4).make bzImage//编译内核
5).make modules//编译模块
6).make modules_install //把模块复制到需要的目录中
7).depmod -a //生成模块间的依赖关系
4.装载内核
1).将linux/arch/i386/boot/bzImage拷贝到/boot下
2).df//查看boot挂载分区
3).修改/boot/grub/grub.conf
title linux-*.*.*(启动时的选择项)//灰色表示修改的地方
root(hd0,0)
kernel /bzImage ro root=/deb/hda2
initrd /initrd-*.*.*.img //***原内核版本
系统调用、标准I\0
1.API和系统调用
从编程这的观点看:API和系统调用之间没有什么区别,都是函数的调用,关注的主要是函 数名、参数和返回值;
从设计者的观点看:API是操作系统为用户程序的实现提供的一些函数,是在库函数中实现
的;系统调用是内核提供给用户程序的一些接口,其实现是在内核中完成的;
2.int main() //打印结果hahahaha
{
printf("haha"); //printf(“haha\n”);打印结果是haha
fork();
// exit(0);_exit(0);
return 0;
}
printf是基于标准I/O的行缓冲,打印字符串“haha”前,会被放到标准I/O的缓冲区,直到缓冲区中出现“\n”(缓冲区被flush)或者缓冲区满为止;而这个缓冲区位于用户进程的空间.而fork()语句会把用户进程空间完整的复制一遍,生成子进程的用户进程空间,包括标准I/O的缓冲区,所以此时主进程、子进程空间的缓冲区中都有“haha”所以会打印两次;
write()不带缓冲区;标准输出:行缓冲;普通文件:全缓冲;
进程控制
1.主进程和fork()子进程对变量的修改不会受到各自的影响(不共享数据空间);不然不用进程通信;若是vfork()(使子进程先执行)则在调用exec或exit之前,他在父进程的空间中运行,这样它对变量的改变会影响到主进程;
2._exit():不会处理缓冲区;exit()处理缓冲区(刷新缓冲区)
3.exec族
int execl( const char *path, const char *arg, ...,(char *)0 );
第一个参数:通常是字符串(代表的文件路径);接下来的参数:执行该文件时传递 过去的参数;最后一个参数必须用空指针(NULL)作结束;如果用常数0表示一个 空指针则必须将其强制转换为一个字符指针
返回值如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于 errno中;
eg..execl(“/bin/ls”,“ls”,“-al”,“/home”,(char * )0);
int execlp( const char *file, const char *arg, ...,(char *)0 );
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后 便执行该文件,参数和返回值参考execl();
eg.execlp(“ls”,“ls”,“-al”,”/etc/passwd”,(char *)0);
4.pid_t wait(int *status)
调用了wait,就会立即阻塞自己,由wait自动分析是否当前进程的某个子进程 已经退出,直到有一个出现为止。参数status用来保存被收集进程退出时的一些 状态,但如果子进程是怎么死的就可以设定这个参数为NULL;
eg.pid = wait(NULL);如果调用成功,wait会返回被收集的子进程的进程ID,如 果调用wait()的进程没有子进程或子进程已经结束则调用就会失败,返回-1
pid_t waitpid(pid_t pid,int *status,int options);可以等待由参数pid指定的子进程
进程通信
无名管道:有亲缘关系的两个进程间通信;有名管道:无亲缘关系的两个进程间通信
1.popen():创建(fork)一个子进程并在子进程中执行第一个参数的程序,同时返回一个管道 的文件指针,第二个参数是要对命令的结果实施的I\0模式的类型
eg.finput=popen("echo test!","r"); //finput指向管道(主进程与子进程 echo之间的管道,子进程echo向管道写,父进程从管道读,即写到父的读端)
foutput=popen("cat","w"); //foutput参数为"w",表示父进程写、 子进程读,将文件流中的数据写入子进程的标准输入。
//echo的输出重定向到cat的输入,通过两个管道(子进程和主进程间),一个buff通信
read(fileno(finput),buff,strlen("test!"));
//fileno()用来获得文件流的文件描述符
write(fileno(foutput),buff,strlen("test"));
pclose(finput);
pclose(foutput);
2.建立无名管道:
int pipe(int fd[2]):头文件:unistd.h;参数:一个有两个元素的整型数组;返回值: 返回-1则创建失败;
eg.if( pipe(fd) == -1 ) ; //pd[0]:读端;p[1]:写端;
{
perror("pipe");
exit(1);
}
write(fd[1],buff,size);
//把buff中的数据写入到管道,返回-1则表示写失败; read(fd[0],buff,size);
//从管道中读取数据到buff中,返回-1则表示读取失败;
3.建立有名管道:
int mkfifo(const char *pathname,mode_t mode):头文件:sys/types.h、sys/stat.h
参数:第一个:管道名字以及管道绝对路径(这个文件不能存在),第二个:对管 道操作的模式,可以参考open()函数中的mode参数;
eg.if( mkfifo( FIFO,O_CREAT|O_EXCL ) < 0 )//当前路径下建立管道
{ //管道名是FIFO
perror(“mkfifo”);
exit(1);
}
有名管道的读写:
为写打开管道: if( (fd=open( FIFO,O_WRNOLY|O_NONBLOCK )) == -1 )
{
perror(“open”);
exit(1);
}
为读打开管道: fd=open(FIFO,O_RDONLY|O_NONBLOCK );
//无NONBLOCK:只写(只读)open要堵塞直到有其他进程为读(只写)而打开这个管道
//有NONBLOCK:只写open之前若没有其他进程已经用只读open打开这个管道,则返回-1错
只读open之前若没有其他进程已经用只写open打开这个管道,则立即返回
4.dup()、dup2():将文件描述符重定向到新的文件中
eg.pipe(fd); //创建一个无名管道
close(fileno(stdout)); //关闭标准输出设备
dup(fd[1]); //标准输出设备重定向到管道的写端, 即所有写向标准输出的数据都将写入管道中;
eg.if( dup2(fd,fileno(stdout)) == -1 ) //重定向输出设备
{
perror("dup2");
exit(1);
}
5.unlink():eg.unlink("FIFO_NAME");删除管道文件;若删除时还有其他进程对该管道进行 操作,则等到其他进程对该管道的操作结束后再删除该管道文件;
信号中断处理
1.信号的发送和捕获
kill:向指定进程发送指定信号;
eg.kill(pid,SIGABRT) //向进程pid发送信号SIGABRT;
eg.kill -SIGCONT 2488 //shell命令
raise:给自己发送一个信号;
eg.raise(SIGUSR1)//将信号SIGUSR1发送给当前进程的代码段;
alarm:等待特定时间后向自己发送信号SIGALRM(此信号的缺省动作为终止),但可以用 signal()将此信号转为某个函数的执行;
eg.alarm(1); //从此处开始1秒后执行函数fucn();
signal( SIGALRM,fucn() );
pause:将进程挂起直到捕捉到信号为止;
eg.alarm(1);//从此处开始暂停一秒;
pause():
2.信号与信号集的处理:
signal:用于指定信号的处理函数signal(signo,func):当信号signo到来时执行函数func;
func还可以取:SIG_IGN:表示忽略该信号;
取:SIG_DFL:采用默认方式处理该信号;
sigemptyset(set):初始化信号集合并将set设置为空;
eg.sigset_t intmask; //设置集合;
sigemptyset(&intmask) //初始化信号集合intmask,并将其设置为空
sigaddset(set,signo):将信号signo加入到信号集合中; eg.sigaddset(&intmask,SIGINT);//将信号SIGINT加到集合intmask中;
sigprocmask(how,set,oset):将指定的信号集合set加到进程的信号阻塞集合中,或从中删 除;如果提供了oset则当前进程的信号阻塞集合将被保存到oset中,how决定 函数的操作方式
how可以取SIG_BLOCK:增加一个信号集合到当前进程的阻塞集合中;
取SIG_UNBLOCK:从当前阻塞集合中删除一个信号集合;
取SIG_SETMASK:将当前信号集合设置为信号阻塞集合;
eg.sigprocmask(SIG_BLOCK,&intmask,NULL);//将信号集合intmask加入到当前 进程的信号阻塞集合中;
sigprocmask(SIG_UNBLOCK,&intmask,NULL);//将信号集合intmask从当前进程的 信号阻塞集合中删除;
消息队列:多线程间通信;头文件:sys/msg.h
消息队列是消息的链表,存放在内核中并由IPC标识符标识。每个消息队列都有结构与其关联用以得到或者设置消息队列的各种属性;
1.创建消息队列:int msgget(key_t key,int flag)
创建成功会返回key所对应的队列的标识符,失败会返回-1;key通过ftok生成
key由内核转换成标识符;
flag可以取:IPC_CREAT|IPC_EXCL|权限位 //创建消息队列
取:0 //打开已经存在的消息队列;
eg.key=ftok(“.”‘r’);//第一个参数是文件名;第二个参数为非0整数
//key:占4个字节;它的高8为是‘r’,其十六进制是0x72
//所以在这里key的值是[72xxxxxx],如[72006e2a]
2.消息的发送和读取:
int msgsnd(int msqid,const void *ptr, size_t nbytes,int flag);
eg.msgsnd(msgid,&msg,size,0)
//msg:要发送的消息;msgid:消息队列ID;size:消息数据的大小并不是消息 //结构的大小;消息数据可以是不超过消息队列限制的任一缓冲区;0:发送消息 的时候不阻塞
ssize_t msgrcv(int msgqid, void * ptr ,size_t nbytes, long type, int flag);
eg.msgrcv(msgid,&msg,size,type,0)
//msgid:要读取的消息队列;msg:保存读取的消息;size:读取的大小
//type:指明了想要得到那种消息:
type==0 返回队列第一个消息;
type>0返回队列消息类型为type的第一个消息
type<0返回队列中消息类型小于或等于type绝对值的消息,如果这种消息有 很多,那么返回类型值最小的消息;
//通常type取>0,则类似链表的节点标号;
//flag可以取MSG_NOERROR:当消息中的数据大于nbytes则不会出错而是消息
中的数据被截短;
取0:忽略该参数;
取IPC_NOWAIT:不阻塞,调用进程会立即返回,没消息就返回-1;
线程基本操作;头文件:pthread.h ;编译是加参数 -lpthread(pthread库)
类似于函数调用
1.创建线程:
int pthread_create(pthread_t *thread,pthread_att_t *attr,void *(*start_rtn)(void),void *arg )
eg.void *fn(void *arg);//要按照pthread_creat()中的参数形式定义;
if( (err=pthread_creat(&tid,NULL,fn,NULL) != 0 )
{
perror(“pthread_creat”);
exit(1);
}
//第一个参数tid:创建线程的ID;第二个参数:线程的属性;
第三个参数fn:线程函数名; 第四个参数:fn的参数
//如果线程创建成功则返回0;失败返回非0;
2.线程终止:void pthread_exit(void * retval)只有一个参数:用来保存退出线程的状态
//结束方式类似于exit();
void pthread_join(pthread_t thread,void **pthread_return)
//第一个参数:等待结束线程的ID,第二个参数:存储结束线程的返回值;
3.线程的终止:void pthread_cancel(pthread_t tid)//终止tid所标识的线程 4.线程清理:pthread_cleanup_push( void(*fn)(void *),void *arg );
//void fn(void *arg)
pthread_exit(void *0);
pthread_cleanup_pop(int execute);execute为0时不执行清理函数;
线程通信;头文件:pthread.h
互斥锁;
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr)
//第二个参数:设置为NULL则默认属性初始化
int pthread_mutex_destory(pthread_mutex_t *mutex)
int pthread_mutex_lock(pthread_mutex_t *mutex)//若已经加锁则阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex)//若已经加锁则不阻塞返回EBUSY
int pthread_mutex_unlock(pthread_mutex_t *mutex)
信号量;
int sem_init(sem_t *sem,int pshared,unsigned int value)
//sem:要创建的信号量;pshared:目前只能为0,决定几个线程分享信号量;
value:sem被赋的初值
int sem_wait(sem_t *sem) //sem-1;sem<0则立即阻塞
int sem_trywait(sem_t *sem)//sem<0则返回
int sem_post(sem_t *sem) //sem+1
int sem_getvalue(sem_t *sem)//获取信号量的值
int sem_destory(sem_t *sem)//删除信号量
GPIO、UART 头文件:unistd.h termios.h
1.open(“/dev/gpf/0”,O_RDWR)//打开IO;返回值小于零则出错
ioctl(fd_gpf,GPIO_SET_MULTI_PIN_OUT,0xf0);//设置IO
read(fd,&key1,1); //获取IO状态
write(fd,&key2,1); //改变IO状态
2.open(“/dev/ttyS0”,O_RDWR)//打开串口;返回值小于零则出错
tcgetattr(fd,&opt)//获取串口属性
tcsetattr(fd,TCSANOW,&opt)//设置串口属性,并立即生效
cfsetispeed(&options, B115200); // 设置输入波特率为115200
cfsetospeed(&options, B115200); //设置输出波特率为115200
创建或修改/root/.Vimrc
set tabstop=4
set softtabstop=4
set shiftwidth=4
set autoindent
set cindent
set number
set showmatch
set mouse=a