linux内核编程笔记【原创】-阿里云开发者社区

开发者社区> 桃子红了呐> 正文

linux内核编程笔记【原创】

简介:
+关注继续查看

阅读目录

以下为本人学习笔记,如有转载请注明出处,谢谢

 

1. service用法 oneshot

DEFINE_MUTEX(buzzer_mutex);

 

mutex_lock(&buzzer_mutex);

mutex_unlock(&buzzer_mutex);

 

static void WriteNumber(const char *fileName, int number)

{                                                

         FILE *fp;                                                                                    

         fp = fopen(fileName, "w");                   

         if (fp == NULL) {                            

             LCD_DEBUG("open %s error, errno %d\n", fileName, errno);

             return; 

         }     

        fprintf(fp, "%d", number);

        fclose(fp);

 }

 

service aa /usr/bin/aa
class core
user root
group root
critical
onrestart restart aa
onrestart restart tt

#service bbd /usr/bin/bb
service bb /usr/bin/app_bbl_read
user root
group root
oneshot

 

2.【Shell脚本】怎样表示一个for循环

作者:gnuhpc 
出处:http://www.cnblogs.com/gnuhpc/

在此说一下我常用的两个结构: 
1. 
for i in $(seq 1 100); do 
        echo $i 
done 
2. 
for (( i = 1 ; $i <= 100; i++ )) ;do 
         echo $i; 
done

作者:gnuhpc 
出处:http://www.cnblogs.com/gnuhpc/

 

3.对于关闭抢占的内核接口

看内核接口是同步还是异步,比方说msleep就是异步接口,会休眠让出cpu

mdelay是忙等待,不会让出cpu

如果是同步接口的话,对于单核cpu,就不会出现多进程同时调用同一个接口出错的情况

如果是异步接口的话,就得具体问题具体分析,如果是仅仅避免多个进程调度同一个接口的情况的话,加信号量或者普通的锁就可以,不一定要加互斥锁,

如果是又有中间层调度接口,又有用户态上层调度接口,那么就另当别论了

 

spin_lock这种锁是用来多核cpu共同调用同个接口的问题,

mutex_lock这种是会休眠,同个cpu的互斥锁,如果是进程上下文就可以用,如果是中断上下文就不能用这种锁,因为这种锁会休眠,中断中是不允许休眠的

 

local_irq_save(flags);

local_irq_restore(flags);

 

spin_lock_irqsave(&iproc_bbl->lock, flags);

spin_unlock_irqrestore(&iproc_bbl->lock, flags);

 

4.网上大家经常碰到的不能连接问题:

请在运行-cmd输入netstat -n 查看5222端口是否在建立状态 ESTABLISHED,这个方法来源自网络,部落没有遇到过.另外,还有一个,就是清空本地本地DNS缓存,具体步骤如下:

在windows下运行运行菜单,开始->运行,输入"CMD"进行命令行窗口,然后输入 ipconfig/flushdns 按回车键

 

5.休眠唤醒调试

kernel/power/main.c中可以通过打印链表的信息,在休眠唤醒的时候将每个唤醒的源消耗的时间打印出来

 dpm_run_callback() ----》drivers/base/power

 

6.中断中不可以加入打印

中断处理函数应该避免调用不可重入函数, 因为新的中断可能发生并打断正在执行任务中,如果当前任务调用了一些不可重入的函数,将会产生错误。
一些常用库函数如printf,malloc,free等都是不可重入函数,因为在函数中引用了全局变量, 这个道理因该很容易明白了吧?
例如, printf会引用全局变量stdout,malloc,free会引用全局的内存分配表。

 

arch/arm/kernel/debug.S:157: Error: too many positional arguments

 

7.sys文件节点要注意返回值

static inline ssize_t show_counter_sysfs(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct asiu_pwm_chip *asiu_pwm = dev_get_drvdata(dev);
int i, n;
long value;

n=0;
if(asiu_pwm) {
for (i=0; i<6; i++) {
value = __onepulse_pwm_counter_extend(i);
n += sprintf(buf + n, "pwm_id(%d)----0x%x \n", i, value); 
}
return n;
}
else
return -1;
}

static struct device_attribute sysfs_misc_list[] = {
__ATTR(onepluse_counter,S_IRUGO , show_counter_sysfs, NULL),
};

 

/* tp info show include tp sw version, fw version, cfg csum, hw version */
static ssize_t tp_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
int len = 0;
int retval;
unsigned char config_id[4];

if (NULL == rmi4_data || !f34_ctrl_base_addr)
return -1;
/* Get device config ID */
retval = synaptics_rmi4_reg_read(rmi4_data,
f34_ctrl_base_addr,
config_id, sizeof(config_id));
if (retval < 0) {
dev_err(rmi4_data->pdev,
"%s: Failed to read device config ID\n", __func__);
return -1;
}
len =
scnprintf(buf + len, PAGE_SIZE, "SW:%s\n",
SYNAPTICS_DSX_DRV_VERSION);

/* combine FW and CFG CSUM */
#define SPLIT_TAG "_CFGID"

len +=
scnprintf(buf + len, PAGE_SIZE, "FW:%u%s%02x%02x%02x%02x\n", rmi4_data->firmware_id,
SPLIT_TAG,
config_id[0],
config_id[1],
config_id[2],
config_id[3]);
/*
len +=
scnprintf(buf + len, PAGE_SIZE,
"CFG ID:0x%02x 0x%02x 0x%02x 0x%02x\n", config_id[0],
config_id[1], config_id[2], config_id[3]);
*/
/* add for chipset name */
len += scnprintf(buf + len, PAGE_SIZE, "CHIP NAME:%s\n", "synaptics");

return len;
}

sys 文件节点写函数的时候,sh: write error: Bad address,这种错误一般是return没有返回正确的值,

什么值是正确的呢?那就是count,长度这些才可以,那么系统是怎么识别的呢?要取决于文件系统和echo的实现

static ssize_t test_sysfs_get_report_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
{
    int retval;
    unsigned char command;
    unsigned long setting;
    struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;

    retval = sstrtoul(buf, 10, &setting);
    if (retval)
        return retval;

    printk("zbh 111 \r\n");
    
    if (setting != 1) {
        printk("zbh %s(): ---> %d\r\n", __func__, __LINE__);
        return -EINVAL;
    }

    mutex_lock(&f54->status_mutex);

    retval = test_check_for_idle_status();
    if (retval < 0) {
        printk("zbh %s(): ---> %d\r\n", __func__, __LINE__);

        goto exit;
    }

    if (!test_report_type_valid(f54->report_type)) {
        dev_err(rmi4_data->pdev,
                "%s: Invalid report type\n",
                __func__);
        retval = -EINVAL;
        printk("zbh %s(): ---> %d\r\n", __func__, __LINE__);
        goto exit;
    }

    test_set_interrupt(true);

    command = (unsigned char)COMMAND_GET_REPORT;

    retval = synaptics_rmi4_reg_write(rmi4_data,
            f54->command_base_addr,
            &command,
            sizeof(command));
    if (retval < 0) {
        dev_err(rmi4_data->pdev,
                "%s: Failed to write get report command\n",
                __func__);
        goto exit;
    }

/* tddi f54 test reporting + */
#ifdef F54_POLLING_GET_REPORT

    retval = test_sysfs_get_report_polling();
    if (retval < 0) {
        dev_err(rmi4_data->pdev,
                "%s: Failed to get report image\n",
                __func__);
        printk("zbh 222 \r\n");
        goto exit;
    }

#else
/* tddi f54 test reporting - */

    f54->status = STATUS_BUSY;
    f54->report_size = 0;
    f54->data_pos = 0;

    hrtimer_start(&f54->watchdog,
            ktime_set(GET_REPORT_TIMEOUT_S, 0),
            HRTIMER_MODE_REL);

    retval = count;

#endif
    retval = count; // ===》如果去掉这一行的话,那么echo  1 > get_report 的话就会出现错误 sh: write error: Bad address

exit:
    mutex_unlock(&f54->status_mutex);

    printk("zbh %s(): retval=%d---> %d\r\n", __func__, retval, __LINE__);

    return retval;
}

 

因为bbl会影响打印机,1s=1000000us

Bbl的时钟是32.768kHz,

所以1000000/32768=30us左右

也就是这个时钟的精度是30us,而bbl寄存器读status状态是延时10us,太短了,至少要在一个clock完成后再读,所以改成延时35us,

 

8.shell脚本循环

#!/bin/sh

while true
do
let "i++"
echo "is $i"
done

 

9.查看这些宏CONFIG_SMP在linux内核中是否有定义

#ifndef CONFIG_SMP

要去linux3.6.5目录下.config文件

 

10.书写代码框架注意

goto 和return

 

static int asiu_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,

                            int duty_ns, int period_ns)

{

       struct asiu_pwm_chip *asiu_pwm = to_asiu_pwm_chip(chip);

       struct asiu_pwm_cfg *pwm_cfg;

       unsigned long period_counts, dutyhi_counts;

       unsigned long prescale = 0;

       unsigned long long ticks;

 

       if (pwm_cfg->enabled) {

              /* Change the PWM output with the new config */

        asiu_pwmc_disable(chip, pwm);

              //asiu_pwmc_enable(chip, pwm);

       }

 

 

#ifdef PWMC_DEBUG

       dev_info(chip->dev, "%s : [pwm-%d] duty_ns = %d, period_ns = %d\n",

                            __FUNCTION__, pwm->hwpwm, duty_ns, period_ns);

#endif

 

       if (duty_ns == 0 && period_ns ==0) {

              /* PWM stay low, duty cycle = 0% */

              prescale = 0;

              period_counts = 0;

              dutyhi_counts = 0;

       }

       else if (duty_ns >= period_ns) {

              /* PWM stay high, duty cycle = 100% */

              prescale = 0;

              period_counts = ASIU_PWM_PERIOD_MASK;

              dutyhi_counts = ASIU_PWM_DUTYHI_MASK;

       }

       else {

              ticks = (unsigned long long)period_ns * asiu_pwm->tick_hz;

              do_div(ticks, NSEC_PER_SEC);

              period_counts = ticks;

              prescale = period_counts >> ASIU_PWM_PEROID_WIDTH;

              if(prescale & ~ASIU_PWM_PRESCALE_MASK) {

                     dev_warn(chip->dev, "%s(%d) : period_counts = %d, prescale = 0x%x\n",

                                   __FUNCTION__, __LINE__, period_counts, prescale);

                     return -EINVAL;

              }

              ticks = (unsigned long long)duty_ns * asiu_pwm->tick_hz;

              do_div(ticks, NSEC_PER_SEC);

              dutyhi_counts = ticks;

       }

 

       pwm_cfg = pwm_get_chip_data(pwm);

       if (!pwm_cfg) {

              dev_warn(chip->dev, "fail to get pwm config data\n");

              return -ENOMEM;

       }

 

       pwm_cfg->prescale = prescale;

       pwm_cfg->period_cnt = period_counts;

       pwm_cfg->dutyhi_cnt = dutyhi_counts;

   

       if (pwm_cfg->enabled) {

              /* Change the PWM output with the new config */

             //asiu_pwmc_disable(chip, pwm);

              asiu_pwmc_enable(chip, pwm);

       }

 

#ifdef PWMC_DEBUG

       dev_info(chip->dev, "%s : pwm_cfg->prescale = %d, period_cnt = %d, dutyhi_cnt = %d\n",

                     __FUNCTION__, pwm_cfg->prescale, pwm_cfg->period_cnt, pwm_cfg->dutyhi_cnt);

#endif

       return 0;

}

 

对于如上框架:

进入config函数时先pwm_disable, 然后中间计算,最后enable

但是中间有很多return,我们做接口的目的有个宗旨

函数是为了改变原来的状态的,如果此函数运行失败返回,那么就要还原原来的场景,不要改变原来的场景

如上例子如果用中间用return,一开始执行了disable,那么中间如果执行失败return了,后面就不会执行enable,那么pwm状态就会变了,那么对于这种情况我们要使用goto到后面,然后再进行enable,就算失败了,也要还原之前的场景去enable,所以需要把上一次的值保存起来。

 

11.vim快捷键

vi  -d   a.c   b.c,可以对比

对比过程中,如果拷贝的话,可以用快捷键dp

 

12.对触摸屏中断的理解

触摸屏与cpu是由一个gpio中断口线相连,所有的中断都是由tp那端抛给cpu的,

Tp通过设定各种参数,刷新频率,扫描频率,电容值(即基准点),tp通过计算触摸屏上的点来决定是否发送中断给cpu,如果计算到没点,就不发送中断给cpu,如果计算到有点,那么就会发送中断给cpu,(注意:tp只要上电启动了那么就会一直进行运算),每次触摸屏上只要有按下,不管几个手指都会产生一个中断,抬起又产生一个中断,最小单位产生两个中断,如果是电平中断,一直按着手指,会不停的产生中断,产生中断的时间和次数由tp的运算速度决定,很难去量化,按下的手指越多,tp运算时间越长,至于有时候发现log有10个finger,和10个status状态,那是驱动代码在一个中断产生时遍历了report动作10次,这些finger和status是通过tp寄存器读取到再由驱动上报内核空间,最终通过input子系统发送给用户空间

 

 ===========================================================================================

13.怎么样让编译器对某些函数不再抱怨warning: unused parameter ‘xxx’?

转自:https://segmentfault.com/q/1010000002395334

#define UNUSED_PARAMETER(x) (void)x 

int main(int argc, char **argv)

{

 

// 这两行是为了避免编译报警告

  UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);

}

 

如果可能,请务必用正常方法消除 warning,真的多余就去掉吧

方法一:

void foo(int a) {
    (void)a;
    // ...
}

方法二:

#ifdef __GNUC__
#  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#else
#  define UNUSED(x) UNUSED_ ## x
#endif

void foo(int UNUSED(a)) {
    // ...
}

参考:http://stackoverflow.com/a/12891181

 ===========================================================================================

 

字符串比较时,strncmp   strcmp 需要注意的地方,要注意比较长度 

if ((strlen(ts_keyword) != strlen(fw_ugd->ts_keyid)) ||
strcasecmp(ts_keyword, fw_ugd->ts_keyid)) {
printf("%s: check ts_keyword[%s],fw_ugd->ts_keyid[%s]\n",
__FUNCTION__, ts_keyword, fw_ugd->ts_keyid);
retval = TP_FW_ERR_TS_KEYID_COMPARE;
goto error;
}

 

中断 IRQF_ONESHOT 与 IRQF_SHARED 不能同时使用
当多个设备共享中断时,由于IRQF_ONESHOT会关闭中断线程的中断,而线程一般执行时间会比较长,所以是不允许的
当hardirq函数为NULL时,必须声明IRQF_ONESHOT, 表示threadirq线程中关闭该中断,在某些情况下,这个标志会非常有用
例如:设备是低电平产生中断,而硬中断函数为NULL,如果不使用IRQF_ONESHOT,就会一直产生中断执行NULL函数,中断线程
得不到执行,声明IRQF_ONESHOT后,会执行完线程才使能该中断  


14.devm_request_irq---- 这种架构会自己释放资源,不需要自己释放,交由devr内核链表管理

http://lxr.free-electrons.com/ident?i=devm_request_irq

15.这个网址可以查询内核源码

 

16.rm命令

删除除了 tt.c的所有文件,只保留tt.c不被删除
rm -rf !(tt.c)

 

17.查看当前项目有哪些远程仓库

$ git remote 

bixiaopeng@bixiaopengtekiMacBook-Pro wirelessqa$ git remote origin 

查看远程仓库

$ git remote -v 
bixiaopeng@bixiaopengtekiMacBook-Pro wirelessqa$ git remote -v
origin     git@gitlab.***.com:xiaopeng.bxp/wirelessqa.git (fetch)
origin     git@gitlab.***.com:xiaopeng.bxp/wirelessqa.git (push)


0x1000 16*16*16=4096bit = 4KB


18.堆栈的限制

  堆栈空间的最大值是由setrlimit系统调用确定的,也可以通过bash内建的ulimit命令来设定和查看.

  例如:

  查看当前可使用的最大堆栈(以KB为单位)

  ulimit -s

  8192 //栈的大小默认是8M

  设定为最大的使用堆栈为15KB

  ulimit -s 15

  此时执行ls将会得到一个段错误.

  ls -l /etc/

  total 1040

  Segmentation fault

  通过用strace跟踪ls命令,将发现有如下的系统调用

  getrlimit(RLIMIT_STACK, {rlim_cur=15*1024, rlim_max=15*1024}) = 0

  说明当前可用的堆栈空间,已经不足以运行strace命令了.

 

 

19.Linux驱动调试中的Debugfs的使用简介

http://blog.csdn.net/wealoong/article/details/7992071

 

Linux DebugFS 子目录也是用debugfs_create_dir来实现

http://blog.csdn.net/superkris/article/details/8626517

mount来调试文件节点, sysfs节点调试方法

make menuconfig ----

Global build settings ------

Compile the kernel with Debug FileSystem enabled

 

Make kernel_menuconfig  --------------

Kernel hacking --------

Debug Filesystem

mount -t debugfs none /sys/kernel/debug

 

20.grep 命令

grep -run "\< abc \>"


21.检测内存泄露的方法

Make  kernel_menuconfig

Kernel hacking =======>

[*] Kernel memory leak detector  

(40000) Maximum kmemleak early log entries

 

[*] Compile the kernel with debug info  

 

make menuconfig

[*] Compile the kernel with Debug FileSystem enabled

[*] Compile the kernel with debug information

 

 

开机后

mount -t debugfs none /sys/kernel/debug

cd  /sys/kernel/debug

cat kmemleak

 

make  kernel_menuconfig

这个选项是说明

General setup ================>

Choose SLAB allocator (SLUB (Unqueued Allocator))

(X) SLUB (Unqueued Allocator)

[*] Enable SLUB debugging support

 

22.这里使用slub分配内存比slab更高效

 

我们在调试内核时,如果出现系统响应非常慢的情况

先看有没有死锁,用lockdep来检测

检测出来后再用ftrace来跟踪函数

如果出现kernel内存泄露,可以 用kmemleak来查看,查看前要确认内核使用哪个分配器,一般是slab或者slub

 cat /proc/meminfo     查看内存泄露

 

23.Linux设备驱动之semaphore机制

static noinline void __down(struct semaphore *sem);
static noinline int __down_interruptible(struct semaphore *sem);
static noinline int __down_killable(struct semaphore *sem);
static noinline int __down_timeout(struct semaphore *sem, long jiffies);
static noinline void __up(struct semaphore *sem);

#define DEFINE_SEMAPHORE(name) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}

 

一个核,执行了两个死循环进程,那么这两个进程是通过内核的调度算法去选择要执行哪个进程的,最终会执行arm的指令,这两个进程在单和上是永远不可能同时执行的,MMU里面会有进程id寄存器

 

24.获得内核函数地址的四种方法 

 本文以获取内核函数 sys_open()的地址为例。
   1)从System.map文件中直接得到地址
      $ grep sys_open /usr/src/linux/System.map
   
   2)使用 nm 命令
      $ nm vmlinuz | grep sys_open
   
   3)从 /proc/kallsyms 文件获得地址
      $ cat /proc/kallsyms | grep sys_open
   
   4)使用 kallsyms_lookup_name() 函数
      是在kernel/kallsyms.c文件中定义的,要使用它必须启用CONFIG_KALLSYMS编译内核。
      kallsyms_lookup_name()接受一个字符串格式内核函数名,返回那个内核函数的地址。
        kallsyms_lookup_name("sys_open");

 

方法一、

通过打印函数地址,可以查看函数在哪里调用

例如:

Core.c   drivers\pwm

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)

{

         if (!pwm || period_ns == 0 || duty_ns > period_ns)

                   return -EINVAL;

 

    printk("%s  drivers\pwm Core.c----(%d)\r\n", __func__, __LINE__);

    printk("pwm->chip->ops->config=%p----(%d)\r\n", pwm->chip->ops->config, __LINE__);

         return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);

}

 

终端显示如下:

[   42.550000] pwm->chip->ops->config=c001b0c0----(378)

 

然后可以在

如下目录

Z:\linux-3.6.5

 

中的System.map中找到

c001b0c0  t  asiu_pwmc_config

就调用的是这个函数asiu_pwmc_config

 

方法二、

dump_stack()函数

 

25.打印语句的使用,带颜色的打印

#define RESETCOLOR "\033[0m"
#define GREEN "\033[0;32m"
#define RED "\033[0;31m"
#define LIGHT_RED "\033[1;31m" 
#define YELLOW "\033[1;33m"
#define BLUE "\033[0;34m"
#define LIGHT_BLUE "\033[1;34m" 
#define CYAN "\033[0;36m" 
#define PURPLE "\033[0;35m"
#define LIGHT_PURPLE "\033[1;35m"
#define BROWN "\033[0;33m"
#define WHITE "\033[1;37m"
#define LIGHT_GRAY "\033[0;37m" 
#define DARY_GRAY "\033[1;30m"

printf(YELLOW"**   10. set asiu_pwm while                               **"RESETCOLOR"\r\n");

printf(YELLOW"**"LIGHT_RED" 4. onepluse pwm disable "YELLOW"**"RESETCOLOR"\r\n");

 

RC文件延时方法

wait  /dev/zhangb   随便一个不存在的节点都可以,固定为延时5s 

 

如何增加打印信息---灵活使用宏定义:

#include <stdio.h>
#include <stdlib.h> 

#define qWiFiDebug(format, ...) printf("[WiFi] "format" File:%s, Line:%d, Function:%s \r\n", ##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__);


int main(void)
-{
| qWiFiDebug("aaaaaa -----");
|
| return 0;
|}

打印输出:

  ./a.out 

[WiFi] aaaaaa ----- File:a.c, Line:9, Function:main

 

复制代码
#define RESETCOLOR    "\033[0m"
#define GREEN         "\033[0;32m"
#define RED           "\033[0;31m"
#define LIGHT_RED     "\033[1;31m"
#define YELLOW        "\033[1;33m"
#define BLUE          "\033[0;34m"
#define LIGHT_BLUE    "\033[1;34m"
#define CYAN          "\033[0;36m"
#define PURPLE        "\033[0;35m"
#define LIGHT_PURPLE  "\033[1;35m"
#define BROWN         "\033[0;33m"
#define WHITE         "\033[1;37m"
#define LIGHT_GRAY    "\033[0;37m"
#define DARY_GRAY     "\033[1;30m"

#define ZBH_TRACE_DEBUG            (1 << 0)
#define ZBH_TRACE_INIT                (1 << 1)
#define ZBH_TRACE_INT              (1 << 2)
#define ZBH_TRACE_X_Y_COORDINATE   (1 << 3)
#define ZBH_TRACE_FINGER_UP        (1 << 4)


#ifdef __BASE_FILE_NAME__
#define printk_get_basename(x)   __BASE_FILE_NAME__
#else
static char *printk_get_basename(char *path)
{
    char *p1 = path, *p2 = p1;
    while (*p1 != '\0') {
        if (*p1 == '/')
            p2 = p1 + 1;
        p1++;
    }
    return (p2);
}
#endif

//printk(KERN_INFO "[%s]"format"File:%s, Line:%d, Function:%s \r\n", \
        //      ##__VA_ARGS__, printk_get_basename(__FILE__), __LINE__, __FUNCTION__); \
//printk(KERN_INFO "[%s%4d@%18s] "format, GT1X_PREFIX, __LINE__, printk_get_basename(__FILE__), ##arg); \
//printk(KERN_INFO "[%s]"format"[File:%s, Line:%d, Function:%s] \r\n", ZBH_PREFIX, ##arg, printk_get_basename(__FILE__), __LINE__, __FUNCTION__); \

#define ZBH_PREFIX   "ZBH: "
#define zbh_trace(flag, format, arg...) \
do { \
    if (zbh_trace_param & flag) \
        printk(KERN_INFO "[%s%4d@ %s] %s(): "format, ZBH_PREFIX, __LINE__, \
            printk_get_basename(__FILE__), __FUNCTION__, ##arg); \            
} while (0)

#define zbh_printk(format, arg...) \
        printk(KERN_INFO "%s"format, ZBH_PREFIX, ##arg)
复制代码

 

 

26.linux用户栈和内核栈的设置

http://stackoverflow.com/questions/2562602/how-does-fork-return-for-child-process

http://blog.csdn.net/u011279649/article/details/18795547

copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct * p, struct pt_regs * regs)

How to set the new process entry

int

copy_thread(unsigned long clone_flags, unsigned long stack_start,
        unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
{
    struct thread_info *thread = task_thread_info(p);
    struct pt_regs *childregs = task_pt_regs(p);

    *childregs = *regs;
    childregs->ARM_r0 = 0;
    childregs->ARM_sp = stack_start;

    memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
    thread->cpu_context.sp = (unsigned long)childregs;
    thread->cpu_context.pc = (unsigned long)ret_from_fork;

 

27.makefile编写注意:

EXTRA_CFLAGS += -DDO_TEST_REPORTING

ifeq ($(CONFIG_ENABLE_PCI),y)

EXTRA_CPPFLAGS += -DCONFIG_ENABLE_PCI

endif

 

28.好的网址

http://web.mit.edu/gnu/www/index.html -------》麻省理工大学的校网,gnu  , automake , autoconf

www.yoctoproject.org --------》飞思卡尔搞的非常强大的linux开发环境

 

29.文件系统操作,查看内核一些信息

 cat /proc/meminfo 

/data/app # cat /proc/meminfo 
MemTotal: 60488 kB
MemFree: 19200 kB
Buffers: 0 kB
Cached: 27028 kB
SwapCached: 0 kB
Active: 11276 kB
Inactive: 22708 kB
Active(anon): 11256 kB
Inactive(anon): 13432 kB
Active(file): 20 kB
Inactive(file): 9276 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 6976 kB
Mapped: 2832 kB
Shmem: 17732 kB
Slab: 3448 kB
SReclaimable: 668 kB
SUnreclaim: 2780 kB
KernelStack: 496 kB
PageTables: 312 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 30244 kB
Committed_AS: 46220 kB
VmallocTotal: 319488 kB
VmallocUsed: 21720 kB
VmallocChunk: 294908 kB

/data/app # cat /proc/mtd 
dev: size erasesize name
mtd0: 000c0000 00020000 "boot"
mtd1: 00080000 00020000 "nvram_fac"
mtd2: 000c0000 00020000 "boot_res"
mtd3: 00400000 00020000 "kernel"
mtd4: 00600000 00020000 "ramdisk"
mtd5: 00600000 00020000 "base"
mtd6: 06e00000 00020000 "data"

 

30.find 命令和grep命令

 find . "*sdio*" -maxdepth 2

find . README -maxdepth 1 | xargs grep -nri "a"

find target/linux/brcm5830/files/arch/arm/mach-iproc/pm_iproc/ -name "*.c" -print | xargs grep "USB"

find ./package/kmod-prolin/bbl/ -maxdepth 1 -print | xargs grep -rni "PCI" 

find ./ -name "synaptics_dsx_core.h"  | xargs grep -rwi "reset_device"

 find ./package/kmod-brcm5830x/input/keypad_matrix/src/keypad_matrix.c -print0 |xargs grep -run -B8 -A2 "buzzer_level"

 find ./ -name "*.c" |xargs grep --colour -run printf

dev_dbg(rmi4_data->pdev,
"%s: rmi4_data->report_type = %d\n"
"rmi4_data->finger_limit = %d\n"
"fhandler->num_of_data_points = %d\n",
__func__, rmi4_data->report_type,
rmi4_data->finger_limit, fhandler->num_of_data_points);

 

复制代码
这是个小技巧,grep的A(after,后)选项和B(before,前)选项可以同时输出其匹配行的前后几行。

比如包含有如下文本的message.txt:

Aug 5 02:43:12 zion kernel: [ 0.000000] Zone PFN ranges: Aug 5 02:43:12 zion kernel: [ 0.000000] DMA 0 -> 4096 Aug 5 02:43:12 zion kernel: [ 0.000000] Normal 4096 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] HighMem 130730 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] early_node_map[1] active PFN ranges Aug 5 02:43:12 zion kernel: [ 0.000000] 0: 0 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] DMI 2.3 present.

用带-B1和-A2选项的grep匹配搜索"DMA"。

grep -B1 -A2 "DMA" message.txt

输出:

Aug 5 02:43:12 zion kernel: [ 0.000000] Zone PFN ranges: Aug 5 02:43:12 zion kernel: [ 0.000000] DMA 0 -> 4096 Aug 5 02:43:12 zion kernel: [ 0.000000] Normal 4096 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] HighMem 130730 -> 130730

grep匹配一个结果,输出多行的功能,在搜索日志文件时很有用。
复制代码

 

 

复制代码
Linux下find一次查找多个指定文件或者排除某类文件,在 GREP 中匹配多个关键字的方法
(1)Linux下find一次查找多个指定文件:
查找a.html和b.html
find . -name "a.html"  -name "b.html"  

find . -regex '.*\.txt\|.*\.doc\|.*\.mp3'
find . -regex '.*\.txt\|.*\.doc\|.*\.mp3'  
./a.txt  
./a.doc  
./a.mp3  

(2)排除某些文件类型:
排除目录下所有以html结尾的文件:
find . -type f ! -name "*.html"    

find . -type f ! -name "*.html"       
./ge.bak.02.09  
./ge.html.changed.by.jack  
./a.txt  
./a.doc  
./a.mp3  

(3)排除多种文件类型的示例:
find . -type f ! -name "*.html" -type  f ! -name "*.php" -type  f ! -name "*.svn-base"  -type  f ! -name "*.js"  -type  f ! -name "*.gif"  -type  f ! -name "*.png"  -type  f ! -name "*.cpp"  -type  f ! -name "*.h"  -type  f ! -name "*.o"  -type  f ! -name "*.jpg"  -type  f ! -name "*.so"  -type  f ! -name "*.bak"  -type  f ! -name "*.log"3)在 GREP 中匹配多个关键字的方法:
grep查找多个数字的文件:
-r 递归,-E:正则  -l:只显示文件名
root@116.255.139.240:~/a# grep -r -E '0341028|100081|10086|10001' *  
a.txt:100081  
b.txt:10086  
c/cc.txt:0341028  
c/cc.txt:100081  
c/cc.txt:10086  
c/cc.txt:10001  
c.txt:10001  
d.txt:0341028  

grep -r  -E -l '0341028|100081|10086|10001' *     
a.txt  
b.txt  
c/cc.txt  
c.txt  
d.txt  

多种类型文件示例:
view plainprint?
find . -name "*.html" -o -name "*.js"|xargs grep -r "BusiTree"   
复制代码

 

 

31.printk 调试方法

内核中打印回调函数的名称

 

复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/current.h>
#include <linux/utsname.h>
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/thread_notify.h>
#include <asm/stacktrace.h>
#include <asm/mach/time.h>

// add by zbh
int get_func_name(void *ip)
{    

    printk("[<%p>] %pS\n", (void *) ip, (void *) ip);
    
    printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
        KERN_DEFAULT, raw_smp_processor_id(),
        current->pid, current->comm,
        print_tainted(), init_utsname()->release,
        (int)strcspn(init_utsname()->version, " "),
        init_utsname()->version);
    
    return 0;
}

void *ip = NULL;
ip = keydata->buzzer->enable; printk("[<%p>] %pS\n", (void *) ip, (void *) ip); printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n", KERN_DEFAULT, raw_smp_processor_id(), current->pid, current->comm, print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), init_utsname()->version); keydata->buzzer->enable(keydata,freq,duty);


再在panic.c中 找到print_tainted
EXPORT_SYMBOL(print_tainted);
这样可以给其他驱动调用此函数

复制代码

 

 

 

 

print_hex_dump ===>内核一个不错的打印方式

此网址是我记录的一个printk 打印函数地址的方法

 http://www.cnblogs.com/sky-heaven/p/7161373.html

    unsigned char input[0x28];
    unsigned char output[0x28];

        print_hex_dump(KERN_CRIT, "bbl_ram@ ", DUMP_PREFIX_OFFSET,
                       16, 1, output, sizeof(output), true);
        printk("\n"); 

 

 __builtin_return_address

http://www.cnblogs.com/sky-heaven/p/7161404.html

printk("\033[1;31m %p---%pS \033[0m\r\n", __builtin_return_address(0), __builtin_return_address(0));

 

 

复制代码
#define BF3005_PREFIX   "bf3005: "
#define bf3005_trace(flag, format, arg...) \
do { \
    if (bf3005_trace_param & flag) \
        printk(KERN_ERR "[%s%4d@%18s] "format, BF3005_PREFIX, __LINE__, printk_get_basename(__FILE__), ##arg);  \
} while (0)

#define bf3005_printk(format, arg...) \
    printk(KERN_ERR "%s"format, BF3005_PREFIX, ##arg)

bf3005_trace(BF3005_TRACE_DESCR, "enter %s(initialized = %d)\n",
             __func__, bf3005->initialized);
复制代码

 

 

方法1:

//#define MY_DEBUG
#ifdef MY_DEBUG
#define MY_DBG(x...) do{printk(x);}while(0)
#else
#define MY_DBG(x...)
#endif

 

方法2:

驱动可以如下写:

#define MY_LEVEL1 (1 << 0)
#define MY_LEVEL2 (1 << 1)

unsigned int my_trace_param=0;
module_param_named(trace, my_trace_param, uint, S_IRUGO|S_IWUSR);


#define MY_DBG(flag, msg...) \
do { \
if (my_trace_param & flag) \
printk(KERN_ERR "zbh-debug: " msg); \
} while (0)

 

MY_DBG(MY_LEVEL1, "Goodbye module exit1.\r\n");
MY_DBG(MY_LEVEL2, "Goodbye module exit2.\r\n");
MY_DBG(MY_LEVEL2, "Goodbye module exit3.\r\n");

 

测试:

insmod my_printk_driver.ko 

echo 2 > /sys/module/my_printk_driver/parameters/trace 

这样就可以选择到底打印哪一条语句,用来动态调试开关,默认关打印

 

 

 

code:

 View Code

 

 32.container_of的用法

typedef struct
{
u32* row_gpios;
u8 row_size;
u32* col_gpios;
u8 col_size;
tKEYCODE* keytable;
u16 keytable_size;
u8 debounce_ms;
int bl_gpio;
int buzzer_gpio; /* if gpio dimming */
int buzzer_pwm_id; /* if pwm controllor */
int ped_enable;
struct delayed_work work;
char * amp_pwr;
HOT_KEY_TAB *hot_key_table;
int hot_key_table_size;
struct delayed_work hot_key_work;
}tKEYPAD_MATRIX_DATA;
#endif

INIT_DELAYED_WORK(&matrix_global_dat.key_data->hot_key_work, hot_key_scan);

static void hot_key_scan(struct work_struct *work)
{
int index;
int has_evnet=0;
tKEYPAD_REPORT_DATA report_key;

tKEYPAD_MATRIX_DATA *keypad = container_of(work,tKEYPAD_MATRIX_DATA, hot_key_work.work);

if(get_hot_key_scan_code(keypad))

}

 

INIT_WORK(&wnet_power_on_wq, gprs_mu709_power_on);

schedule_work(&wnet_power_on_wq); 
flush_work(&wnet_power_on_wq); //  flush_work可以阻塞,是同步机制,如果去掉此函数就是异步机制

static void gprs_mu709_power_on(struct work_struct *work __attribute__((unused)))
{
gprs_mu709_opt(WNET_POWER_ON_WQ);
}

 

vim使用

Vim

zR  全部展开

zM全部合并

 

 

vim  快捷键

shift   +  i      (‘I’)    进行编辑

shift   +  4     (‘$’)    跳到行尾

shift   +  v      (‘V’)   选中行 

shift   +  0      (‘)’)    跳到行首

 

先ctrl  +  v  模块编辑

再s,或者shift + $, shift + i进行编辑即可,编辑完后就esc就可以更改局部内容

s    删除

 

 

Ctrl+wl或wh是切换窗口来编辑

 

 

vs a.c 打开一个文件

 

BundleSearch 查找所有插件,找到后,yy复制想要的那一行插件到vimrc中即可vi ~/.vimrc

然后再执行BundleInstall

BundleList 当前插件

 

vim安装后,要把.vimrc放在里面保存即可,然后还有几个隐藏的文件夹也要放在里面

 

查看函数被哪些调用的话,快捷键:ctrl+\ ,然后再按s即可

或者cs find main也可以

 

先要安装了ctags,在程序的根目录下运行ctags -R,生成tags文件,然后在编辑程序时按Ctrl+]就会跳转到当前光标所在东西的定义处。若有多个tag,执行:ts,进行选择。按Ctrl+o即可跳回。不过,当修改过代码后,需要重新生成tags。

 

33.git操作,检查代码log技巧

Linux kernel  的官方 GIT地址是:

http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git

可以从这个地址拿到 kernel 的 代码仓库。

git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git 

 

在家目录下(也就是自己的目录下)

将git执行文件放在家目录的bin下面,没有就自己创一个bin目录

将文件git-completion.bash修改文件名为 .git-completion.bash

在家目录下的.bashrc 的最后一行增加source  ~/.git-completion.bash

 

source .bashrc

source .profile

这样git就有了补全功能

git-completion.bash文件里面有说明。

 

git remote -v

如果是跟踪着某个开发者的git代码库,

 

git blame <文件名>

然后, 找出感兴趣行上的commit ID  ,用

git show  <commit ID>

 git log --pretty=oneline  b.c 

查看这次改动是由哪次提交引入的.一般可能会附加提交说明,

解释这次提交的初衷,作用等.

 

还可以记下作者的名字 

 

然后放狗(google)搜: lkml +作者名字+关于这个修改或主题的一两个重要关键词,

这样可能可以直接搜到当时提交时作者发在内核列表的邮件,可能有更详细的讨论.

 

这么做去找找引入这些重要变化的源由.

 

34.内核关抢占

复制代码
 Symbol: PREEMPT_NONE [=y]                                                                                                                            |  
  | Type  : boolean                                                                                                                                      |  
  | Prompt: No Forced Preemption (Server)                                                                                                                |  
  |   Defined at kernel/Kconfig.preempt:6                                                                                                                |  
  |   Depends on: <choice>                                                                                                                               |  
  |   Location:                                                                                                                                          |  
  |     -> Kernel Features                                                                                                                               |  
  |       -> Preemption Model (<choice> [=y])   
复制代码

 

35. 处理DDR跑飞问题:

某些处理器可以处理,如果是系统休眠唤醒后出现系统乱飞的情况,可以在休眠前对DDR进行CRC校验,唤醒后再进行一次校验,两次一样即可,但是必须保证DDR无任何操作。

 

36.开机自启动,需要用脚本启动脚本,rc文件中

 #camera drivers
   if property:ro.fac.camera_number!= chmod 755 /startup/camera_drv_load.sh
   if property:ro.fac.camera_number!= exec /startup/bin/sh /startup/camera_drv_load.sh

 

37.一个拆包的方法,i2c

 View Code

 

38.网络配置相关命令

udhcpc -i usb0

route

ping www.baidu.com -I usb0

有时ping不通,可以试下只保留lo和usb0,其余的全down掉

 

一种拆包算法

 View Code

 

 

39.windows下保存网页的方法:

ctrl + p  就是打印,然后选择adobe PDF,确定 即可

 

40.gcc编译器内置选项

 arm-none-linux-gnueabi-gcc -E -dM -< /dev/null

 

 View Code

 

 

 

linux-3.6.5/scripts

vi gcc-x86_32-has-stack-protector.sh

复制代码
#!/bin/sh

echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
if [ "$?" -eq "0" ] ; then
        echo y
else
        echo n
fi
复制代码

%gs为栈保护

41.如果反汇编后有%gs,就说明内核有栈保护

arm_build.sh

arm-none-linux-gnueabi-gcc -S -fstack-protector -o stack test_stack_protector.c

test_stack_protector.c

int foo(void) { char X[200]; return 3; }

./arm_build.sh

vi stack

 View Code

 

42.为了保证代码不乱序,内存屏障的建立

 #define readb(c)        ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c)        ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c)        ({ u32 __v = readl_relaxed(c); __iormb(); __v; })

eg:

aaa();

wmb();

bbb();

 no_console_suspend

initcall_debug 

说明initcall_debug是一个内核参数,可以跟踪initcall,用来定位内核初始化的问题。在cmdline中增加initcall_debug后,内核启动过程中会增加如下形式的日志,在调用每一个init函数前有一句打印,结束后再有一句打印并且输出了该Init函数运行的时间,通过这个信息可以用来定位启动过程中哪个init函数运行失败以及哪些init函数运行时间较长

 休眠唤醒调试还可以打开【Power management options】===》

[*] Power Management Debug Support | | 
| | [*] Extra PM attributes in sysfs for low-level debugging/testing | | 
| | [*] Test suspend/resume and wakealarm during bootup

 

43.网络 netstate

netstate –nao

 

svn co svn:xxx --depth=empty

 ls

 svn ls

 cd aa/

 ls

 svn ls

 svn up release_branches --depth=empty

 cd release_branches/

 ls

 svn ls

 svn up xxx

 

44.内核异步通知


retval = request_irq(pdev->irq, MioSoC_isr, IRQF_SHARED  , "MioSoC", pmio);

中断处理程序:
static irqreturn_t MioSoC_isr(int irq, void *data)
{
    
    struct MioSoC_device *dev = data;
    spin_lock(&dev->regs_lock);
        dwIntStatus = inw(pmio->caddr +0x4c); // 读取卡上的控制缓存器中断状态
            if (dwIntStatus & 0x4)              // 检查是否为本卡的中断
            {
                outw((dwIntStatus & (~0x43)),pmio->caddr+0x4c);
                if (pmio->async_queue )
                        kill_fasync(&dev->async_queue, SIGIO, POLL_IN); //发出异步通知信号
                outw(dwIntStatus,pmio->caddr + 0x4c);
            }
    spin_unlock(&dev->regs_lock);
     wake_up_interruptible(&dev->wait);
    return IRQ_HANDLED;
}

 

45.线程处理,线程安全

futex

 

46.unicore32

unicore32的代码写的很好,可以参考

47.defio 双缓冲机制

48.strace命令

strace -o t.log ./a.out

49.Linux上搭建web服务器,实现web控制嵌入式设备

随着Internet技术的兴起,在嵌入式设备的管理与交互中,基于Web方式的应用成为目 前的主流,这种程序结构也就是大家非常熟悉的B/S结构,即在嵌入式设备上运行一个支持脚本或CGI功能的Web服务器,能够生成动态页面,在用户端只需 要通过Web浏览器就可以对嵌入式设备进行管理和监控,非常方便实用。

路由器上现在不用boa服务器了,一般用uhttpd和goahead,这样可以对CGI进行控制

 

50. 内核中的set_freezable与wait_event_freezable_timeout,进程等待

到目前为止,我们的控制线程就已经分析完了,不过我们发现,这个控制线程是在usb_stor_acquire_resources中定义的,在usb_stor_acquire_resources之后,我们还创建了usb_stor_scan_thread线程,这是一个扫描线程。

static int usb_stor_scan_thread(void * __us)

{

    struct us_data *us = (struct us_data *)__us;

    printk(KERN_DEBUG

            "usb-storage: device found at %d\n", us->pusb_dev->devnum);

    set_freezable();  //设备在一定时间内没有响应,会挂起

    if (delay_use > 0) {  // delay_use秒后如果U盘没拔出则继续执行,否则执行disconnect

            printk(KERN_DEBUG "usb-storage: waiting for device "

                          "to settle before scanning\n");

                  wait_event_freezable_timeout(us->delay_wait,test_bit(US_FLIDX_DONT_SCAN, &us->dflags), delay_use * HZ);

    }

    if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {

            if (us->protocol == US_PR_BULK &&

                          !(us->fflags & US_FL_SINGLE_LUN)) {

                  mutex_lock(&us->dev_mutex);

                  us->max_lun = usb_stor_Bulk_max_lun(us);  //询问设备支持多少个LUN

                  mutex_unlock(&us->dev_mutex);

            }

            scsi_scan_host(us_to_host(us));

            printk(KERN_DEBUG "usb-storage: device scan complete\n");

    }

    complete_and_exit(&us->scanning_done, 0);  //本进程结束,唤醒disconnect中的进程

}

对于上面这个扫描线程,里面的usb_stor_Bulk_max_lun函数完成了主机控制器与设备之间的第一次通信。USB驱动程序首先发送一个命令,然后设备根据命令返回一些信息,这里显示的是一个表示LUN个数的数字,usb_stor_Bulk_max_lun完成的是一次控制传输。

 

51.Linux resume

linux的resume是根据device的加载顺序来执行的

52.setup_time中断

这种虽然是软中断处理,但一样是中断上下文,不可以在处理函数中休眠,或者发生进程调度的事情,这样会死机,workqueue.c中只有一种机制才可以这样做,tasklet

53.休眠唤醒

休眠唤醒除了在配置文件中cmdline增加no_console_suspend,还可以开机如下操作,即可打印出休眠唤醒的全部log

echo N > /sys/module/printk/parameters/console_suspend

54.pwm使用

// disable pwm 的正确流程是:

pwm_config(prn_stb_pwm, 0, period_ns); ===》这样才是安全的

pwm_disable(prn_stb_pwm);

而不是:

pwm_disable(prn_stb_pwm);

 

55. 算一张表里有多少个1

hweight8

 

56.通过Sys节点名字反查pid

fs/sysfs/file.c

sysfs_open_file() ======>

    char *name1, *name2;

    name1 = "buzzer_user_trigger";
    name2 = "buzzer_keypad_enable";
    if ((0 == strncmp(attr_sd->s_name, name1, strlen(name1))) ||
        (0 == strncmp(attr_sd->s_name, name2, strlen(name2))) ) {
        printk("zbh %s():--->%s (%d) \r\n", 
            __func__, attr_sd->s_name, __LINE__);
        printk("zbh %s():--->pid=%d (%d) \r\n", 
            __func__, current->pid, __LINE__);
    }

 

57.文件系统知识点

cat /proc/filesystems

 

58.spi透传?

spi能否透传?如果master与slave不对称,一边带宽高,一边带宽少,从机接收的时候接收不过来,如果要用dma方式,并且协定好底层数据传输大小,每次发送时候要发送数据长度

 可以参考stm32官网的 spi IAP固件升级的例程代码

 

欢迎交流,如有转载请注明出处

新浪博客:http://blog.sina.com.cn/u/2049150530
博客园:http://www.cnblogs.com/sky-heaven/
知乎:http://www.zhihu.com/people/zhang-bing-hua

 













本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5279334.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9990 0
Java之网络编程笔记
网络通讯要素: 1.IP地址     IP地址:用于标记一台计算机的身份证。 IP地址由网络地址(确定网络)和主机地址(网络中的主机)组成。             IP地址分为A类地址、B类地址、C类地址(常用)、D类地址、E类地址。
712 0
C++MFC编程笔记day06 MFC向导、MFC绘图类使用
 MFC绘图    MFC绘图类包括绘图设备类和绘图对象类    1 绘图设备类      CDC类-父类是CObject,封装的是一般的绘图设备,例如:显示器,            打印机等。
1070 0
UNIX环境高级编程笔记之进程环境
本章讲的都是一些非常基础的知识,目的是为了下一章讲进程控制做铺垫,所以,本章就不做过多的总结了,直接看图吧。
703 0
UNIX环境高级编程笔记之进程控制
  本章重点介绍了进程控制的几个函数:fork、exec族、_exit、wait和waitpid等,主要需要掌握的是父进程和子进程之间的运行机制,怎么处理进程的正常和异常终止、以及怎么让进程执行不同的程序等知识点。下一章将进一步说明一个进程和其他进程之间的关系——会话和作业控制。
678 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13776 0
4269
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载