存档

2009年5月 的存档

南京爱立信部分实习笔试题解析

2009年5月20日 2 条评论

前两天去参加了个南京爱立信的实习的笔试,哎,这活动办的真是无语,等他的考卷就等了40分钟。。。
下面是部分实习笔试题的解析
1. const char *p和char *const p 有什么区别?
答:const char *p是常量指针,表示该指针指向的是一个常量,而char *const p是指针常量,表示该指针自身是一个常量,即该指针所指向的常量的地址不可变。

2. delete p和delete[] p有什么区别?
答:delete p对应于使用new去动态创建对象
delete[] p对应于使用new[]去动态创建对象数组

3. 写一段程序,实现在链表的尾部插入新的节点,可以使用递归的方法
<待完成>

4. 以下程序的输出是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;
void main()
{
	class base
	{
	public:
		base()
		{
			cout << "base::base()\n";
		}
		virtual ~base()
		{
			cout << "base::~base()\n";
		}
		void func()
		{
			cout << "base::func()\n";
		}
	};
 
	class inherited:public base
	{
	public:
		inherited()
		{
			cout << "inherited::inherited()\n";
		}
		~inherited()
		{
			cout << "inherited::~inherited()\n";
		}
		void func()
		{
			cout << "inherited::func()\n";
		}
	};
 
	inherited *ptrD = new inherited;
	base *ptrB = ptrD;
	ptrB->func();
	delete ptrB;
}

答:本题的关键在于理解对象构造以及析构的顺序,构造时先调用父类的构造函数,再调用成员变量的构造函数,接着再调用自己的构造函数。析构时相反。
所以该题的答案为:
base::base()
inherited::inherited()
base::func()
inherited::~inherited()
base::~base()

5. C中~是什么运算符?
答:是取反位运算符

6. 解释下面的语句 int (*p) (char *p)
答:p是一个函数指针,该函数的参数是char*类型,返回值为int

7. ls -l > temp.txt 2 >& 1 解释一下这个命令
答:将当前目录里的文件以列表形式重定向到temp.txt文件中,同时将出错信息打印在标准输出上

8. 现在你在A机器上,需要FTP到B机器/usr/bin下取出二进制文件man到A的/usr/bin下。请写出命令行。
A:>ftp B (have logged in)
ftp>cd /usr/bin
ftp>lcd /usr/bin
ftp>get man
ftp>bye

分类: 实习 标签: , ,

Linux 2.6内核下实现一个操作/proc的内核模块

2009年5月18日 1 条评论

Linux课程实践的一次作业,要求在linux下构建一个在/proc中实现clock文件的模块,该文件支持读操作。
然后开始疯狂的google操作。进而发现整个流程应该是这样的
如果是ubuntu或者fedora发行版,需要配置对应的内核开发环境,而SUSE Enterprise则不用。我用的是ubuntu,在这里就简要的介绍一下ubuntu下内核开发环境的配置。
首先需要安装源build-essential这个包,对应的命令为

sudo apt-get install build-essential

然后再去下载自己的版本所对应的Linux源代码
查看自己的Linux版本的命令为

uname -a

我自己的显示是2.6.27-14-generic
所以应该去下载2.6.27的Linux源代码,命令为:

sudo apt-get install linux-source-2.6.27

好,等这个包安装完成以后,我们进入/usr/src这个目录下将其解压缩,因为默认是把这个文件下载到这个目录下的,你也可以拷贝这个文件到任何你想要放置的位置进行解压
解压完成以后,进入该目录,进行编译操作,命令如下
Step 1:

make mrproper

一下,这个动作是将你使用的源代码包恢复到初始状态
Step 2:
配置内核
保存原有系统配置文件,将/boot/下的config-2.6.27-14-generic拷贝到/usr/src/linux-source-2.6.27(刚下载下来解压的Linux源码下,并把名字改为.config)
对应命令为

sudo cp /boot/config-2.6.27-14-generic /usr/src/linux-source-2.6.27
sudo mv config-2.6.27-14-generic .config

接着进行内核的配置

sudo apt-get install libncurses5-dev

(make menuconfig要调用的)

make menuconfig

当你make menuconfig后,选倒数第二项:Load an alternate configuration file
把.config加载进来,这样你就能在原来内核的基础之上修改了
Step3:

make

让他编译吧,耐心等待,我笔记本性能比较差,要编译两个小时左右的时间
Step4:

make bzImage

Step5:

make modules

Step6:

make modules_install

Step7:

make install

重新启动
至此,内核树就建立啦,我们就可以进行相应的内核模块的开发了
贴上自己的clock.c文件,该文件读取内核时间,然后在/proc目录下创建一个clock文件,在clock文件里打印出系统自1970年1月1日起的秒数和纳秒数,中间用空格隔开

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#define PROCFS_NAME	"clock"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("conan");
 
static struct proc_dir_entry *clock_proc_file;
 
//called when a read is done on /proc/my_clock
int read_time(char *buf,char **start,off_t offset,int count,int *eof,void *data){
 
  struct timespec now;
  int len = 0;
  if (offset > 0)
  {
    printk(KERN_INFO "offset %d : /proc/%s : read_time, \
       wrote %d Bytes\n", (int)(offset),PROCFS_NAME, len);
    *eof = 1;
    return len;
  }
  now = current_kernel_time();
  len = sprintf(buf, "%ld %ld\n", now.tv_sec, now.tv_nsec);
  printk(KERN_INFO "now time is %s\n",buf);
  return len;
}
 
 
//called when module is inserted in system
int init_module(){
  int ret_value = 0;
  clock_proc_file=create_proc_entry(PROCFS_NAME,0644,NULL);
  clock_proc_file->read_proc = read_time;
  printk(KERN_INFO "Trying to create /proc/clock:\n");
  if (clock_proc_file == NULL)
  {
    ret_value = -ENOMEM;
    printk(KERN_INFO "Error: Could not initialize /proc/%s\n",PROCFS_NAME);
  }
  else
  {
    printk(KERN_INFO "Initialize /proc/%s\n",PROCFS_NAME);
  }
  return ret_value;
}
//called to remove module from system
void cleanup_module(){
  remove_proc_entry(PROCFS_NAME,NULL);
  printk(KERN_INFO "/proc/%s removed\n",PROCFS_NAME);
}

接着是这个文件的Makefile
obj-m := clock.o
KDIR = /usr/src/linux-source-2.6.27/
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions
编译的时候千万要注意Makefile和clock.c(不要改名,除非对应的Makefile也改)一定要在一个名字中没有空格的文件夹中,否则就会出现没有找到对应规则的错误!我搞了近两个小时才发现了这个问题。
编译完成之后使用命令insmod clock.ko装载该模块,这个时候就可以
cat /var/log/syslog查看相应的输出信息了,如果模块被正确装载,则会在这个文件的底部出现相应的调试信息。
接着,再是我的测试程序,这个程序对/proc/clock进行了读取,并将读取的值与gettimeofday获取的值作比较。
代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#define MAX 10
#define LENGTH 21
 
int main(){
   int i;
   FILE *my_clock;
   struct timeval gtodTimes[MAX];
   char procClockTimes[MAX][LENGTH];
 
   printf("Please wait for a while, test is running...\n");
   //getting times from both module and system call
   for(i=0;i<MAX;i++){
      my_clock = fopen("/proc/clock", "r");
      if (my_clock == NULL)
      {
         printf("/proc/clock doesn't exist\n");
         exit(1);
      }
      else
      {
         gettimeofday(&gtodTimes[i], NULL);
         fgets(procClockTimes[i], LENGTH, my_clock);
         fclose(my_clock);
         sleep(1);
      }
   }
   //printing data
   for(i=0;i<MAX;i++){
      char *nsec_pointer;
      char *delim = " ";
      nsec_pointer = strtok(procClockTimes[i],delim);
      nsec_pointer = strtok(NULL,delim);
      printf("At iteration %d, Gettimeofday=%lds %ldus, myClock=%ss %sns\n", i,
             gtodTimes[i].tv_sec, gtodTimes[i].tv_usec ,procClockTimes[i],nsec_pointer);
   }
   return(0);
}

Linux VIRTT定时器设置时间与初始时间不一致的问题

2009年5月13日 没有评论

首先,来看一段测试程序,该程序设定了一个virtual 的定时器,然后用getitimer()得到当前的定时器的值
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
struct itimerval virtt;
virtt.it_interval.tv_sec = 1;
virtt.it_interval.tv_usec = 0;
virtt.it_value.tv_sec = 1;
virtt.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &virtt, NULL);

while (1)
{
getitimer(ITIMER_VIRTUAL,&virtt);
printf("tv_sec %ld\n",virtt.it_value.tv_sec);
printf("tv_usec %ld\n",virtt.it_value.tv_usec);
}
return 0;
}

运行程序得到测试结果如下:
tv_sec 1
tv_usec 4062
tv_sec 1
tv_usec 4062
tv_sec 1
tv_usec 4062

//好多好多重复
tv_sec 1
tv_usec 62
tv_sec 1
tv_usec 62
tv_sec 1
tv_usec 62

//好多好多重复
tv_sec 0
tv_usec 996062
tv_sec 0
tv_usec 996062
tv_sec 0
tv_usec 996062
tv_sec 0
tv_usec 996062
//…
//下面继续递减4000us(一个jiffy的值)
OK,为什么明明设置的是1s的定时器,怎么变成了1.004062s了,这多出来的是4062哪来的?让我们看一下Linux的源代码
首先找到do_setitimer这个函数,setitimer调用的就是这个函数,贴个代码片段:
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
struct hrtimer *timer;
ktime_t expires;
cputime_t cval, cinterval, nval, ninterval;

/*
* Validate the timevals in value.
*/
if (!timeval_valid(&value->it_value) ||
!timeval_valid(&value->it_interval))
return -EINVAL;

switch (which) {
case ITIMER_REAL:
...
break;
case ITIMER_VIRTUAL:
nval = timeval_to_cputime(&value->it_value);//使用我们自己设置的定时器的数值,返回一个long赋值给nval
ninterval = timeval_to_cputime(&value->it_interval);
spin_lock_irq(&tsk->sighand->siglock);
cval = tsk->signal->it_virt_expires;
cinterval = tsk->signal->it_virt_incr;
if (!cputime_eq(cval, cputime_zero) ||//如果nval或者cval的值不为0
!cputime_eq(nval, cputime_zero)) {
if (cputime_gt(nval, cputime_zero))//如果nval的值大于0,则给nval加上一个jiffy的时间,这就解释了为什么一开始设置的0一下子多了4000us,那还有多出来的62us是哪来的,让我们再来看一下上面的timeval_to_cputime函数是干什么的,请转到下一段代码片段
nval = cputime_add(nval,
jiffies_to_cputime(1));
set_process_cpu_timer(tsk, CPUCLOCK_VIRT,//开始设置进程的计时器,并将其挂到相应的队列
&nval, &cval);
}
tsk->signal->it_virt_expires = nval;
tsk->signal->it_virt_incr = ninterval;
spin_unlock_irq(&tsk->sighand->siglock);
if (ovalue) {
cputime_to_timeval(cval, &ovalue->it_value);
cputime_to_timeval(cinterval, &ovalue->it_interval);
}
break;
case ITIMER_PROF:
...
default:
return -EINVAL;
}
return 0;
}

下面是timeval_to_cputime的代码片段:

unsigned long sec = value->tv_sec;
long usec = value->tv_usec;

if (sec >= MAX_SEC_IN_JIFFIES){
sec = MAX_SEC_IN_JIFFIES;
usec = 0;
}
return (((u64)sec * SEC_CONVERSION) +
(((u64)usec * USEC_CONVERSION + USEC_ROUND) >>//这里有一个复杂的运算操作,这个值就是上面的nval,具体的宏定义以及这段代码的意思可以去看源码上面的说明
(USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;

紧接着,我们再来研究一下do_getitimer,和do_setitimer相反,这个函数通过调用cputime_to_timeval函数将当前定时器的值赋值给应用程序的timeval结构,下面是代码片段:

u32 rem;

value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
NSEC_PER_SEC, &rem);
value->tv_usec = rem / NSEC_PER_USEC;//这里有一个除法操作,看到这里我猜多出来的62us就是因为上面的复杂运算和这个除法操作共同导致的

OK,现在我们已经从实现上了解了为什么我们设置的定时器一开始的时候与设置的值不同,那么,为什么Linux要这么设计呢?
贴一段因为英文说明:
Implementations may place limitations on the timer value. To make sure that a process gets at least as much time as requested, the timer value is rounded up to the next timer tick (a timer tick is the smallest supported value).
The timer value is rounded up to the next timer tick because, the timer will be initialize somewhere between timer ticks.
If a setitimer() is followed by a getitimer() without a timer tick in between, it is possible that the value returned by getitimer() may be more than the initial value requested by setitimer() due to this rounding.
简单的来说,就是Linux想让一个进程的计时开始时间一定要大于等于我们自己设置的时间。

科学发展观学习心得

2009年5月13日 没有评论

最近在全国各地热火朝天地开展起学习科学发展观的活动。作为南京大学软件学院的学生党员,在学校、学院党委组织下,通过集体学习、听讲座报告、自我学习等形式,我也对胡锦涛同志提出的科学发展观进行了认真、深入地学习。下面是我的个人感受和体会。
一、科学发展观的基本内涵
科学发展观是适合中国国情和顺应时代潮流的发展观,它包括了系统而丰富的内容,它是人们对发展问题的总体认识和根本观点。科学发展观的内涵是十分丰富的,包含了坚持以人为本,是科学发展观的核心内容;坚持改革开放,是科学发展观的强大动力;促进全面发展,是科学发展观的重要目的;保持协调发展,是科学发展观的基本原则;实现可持续发展,是科学发展观的重要体现;实行统筹兼顾,是科学发展观的总体要求等。
“第一要义是发展”。这是基于我国社会主义初级阶段基本国情的,基于人民过上美好生活的深切愿望,基于巩固和发展社会主义制度,基于巩固党的执政基础、履行党的执政使命作出的重要结论。必须始终坚持以经济建设为中心,聚精会神搞建设,一心一意谋发展。
“核心是以人为本”。发展在于人的全面发展。我们党来自于人民,植根于人民,服务于人民。在任何情况下,与人民群众同呼吸共命运的立场不能变,全心全 意为人民服务的宗旨不能忘,坚信人民群众是真正英雄的历史唯物主义观点不能丢。务必继续保持谦虚谨慎、不骄不躁的作风,务必继续保持艰苦奋斗的作风,树立正确的世界观、人生观、价值观,树立正确的权力观、地位观、利益观,做到权为民所用、情为民所系、利为民所谋。
“基本要求是全面协调可持续”。我们讲的发展绝不只是指经济增长,而是要坚持以经济建设为中心,在经济发展的基础上实现社会全面发展。我们要更好地坚持全面发展、协调发展、可持续发展的发展观,更加自觉地坚持推动社会主义物质文明、政治文明和精神文明协调发展,坚持促进人与自然的和谐。在促进发展的进 程中,我们不仅要关注经济指标,而且要关注人文指标、资源指标和环境指标;不仅要增加促进经济增长的投入,而且要增加促进社会发展的投入,增加保护资源和 环境的投入。
“方法是统筹兼顾”。只有坚持统筹兼顾,我们才能真正处理好我国这样一个十几亿人口的发展中大国的改革发展稳定问题,真正处理好全体人民的根本利益和 各方面的利益问题,真正把全体人民和各方面的积极性、主动性、创造性充分发挥出来,为推进党和国家事业形成广泛共识、集聚强大力量。特别要看到,在我国改 革发展的关键阶段,经济体制深刻变革,社会结构深刻变动,利益格局深刻调整,思想观念深刻变化。在这样的情况下,我们要推动科学发展、促进社会和谐,必须更加自觉地运用统筹兼顾的根本方法,正确反映和兼顾不同方面的利益。
二、大学生如何实践科学发展观
第一,要提高学习能力,进一步增强自身素质。作为南京大学软件学院的党员,在学习中,不仅要深入学习课堂知识,保证自己专业课程的学习质量,还要进行大量的课外阅读,保证自己技术的更新,与社会接轨,而不仅仅只是纸上谈兵。在学习中,要有目的,有方向,要进行系统思考、统筹安排。要有一种学习的危机感、紧迫感,把学习知识、提高素质作为生存和发展的紧迫任务,把学习当作一种追求,牢固树立终身学习的观念,不断提高理论水平,提高知识层次。
第二,要提高创新能力,进一步增强自身的综合素质。在学习工作方面,要进行多方位思考,多角度解决问题,提高学习和工作的效率,提高洞察力,努力把课堂上学到的知识进行补充和延伸,充实自己的头脑,提高自己的能力,做一个全面、协调发展的人。作为软件学院的学生党员,我们更应该在提高创新能力上做足功夫,为国家的软件行业早日赶超国际先进水平做出自己的贡献。
第三,要提高自律能力,进一步健全完善自己的人格。我们的一言一行,不仅代表着个人,而且代表着党的形象。我们一定要珍惜党的政治声誉,堂堂正正做人,走好人生之路,树立良好的形象。正确认识自我,培养高尚的人格,始终保持谦虚谨慎、戒骄戒躁的良好作风,以高度的自觉自律精神培养自己的集体主义感、敬业奉献和诚实信用品质、强烈的社会责任感和历史使命感,讲求团结合作,不断超越自我,实现同学间竞争求胜求发展的“双赢”
第四,要提高自身身体素质,进一步增强自己的体魄。作为二十一世纪新一代的大学生,我们是祖国的未来,我们要保证自己的身体素质能够满足祖国发展的需要,要在现在的学习中满足学习的需要,在今后的工作中满足工作地需要,每天坚持进行体育锻炼,强身健体,通过自己的努力争取为祖国健康奋斗五十年。
作为当代大学生的我们,要将深入贯彻落实科学发展观与自身的发展联系起来,从实际出发,坚持实事求是,全面把握科学发展观的科学内涵和精神实质,增强贯彻落实科学发展观的自觉性和坚定性,着力转变不适应不符合科学发展观的思想观念,着力解决影响和制约科学发展的突出问题,把全社会的发展积极性引导到科学发展上来,把科学发展观贯彻落实到经济社会发展各个方 面。当然我们也应该看到推动科学发展是一个长期的历史任务,只能分阶段、有层次地循序推进。贯彻落实科学发展观,更要求我们客观冷静地求真务实,坚持不懈地开拓前进,扎扎实实脚踏实地地团结奋斗,从而一步一个脚印地达到预期的目标。

Hello world to岚涟小筑

2009年5月13日 没有评论

Hi, everyone~~~

It’s my new wordpress blog here

From today on I will share my life with you

Enjoy it~~~

Hello world!

2009年5月10日 1 条评论

欢迎使用 WordPress 。这是系统自动生成的演示文章。编辑或者删除它,开始您的博客!

分类: 未分类 标签: