现在的位置: 首页 > 综合 > 正文

smp_processor_id()

2013年09月20日 ⁄ 综合 ⁄ 共 3512字 ⁄ 字号 评论关闭

smp_processor_id()用于返回当前处理器的id号

unsigned int smp_processor_id(void)
{
    unsigned long preempt_count = preempt_count();
    int this_cpu = __smp_processor_id();
    cpumask_t this_mask;
    if (likely(preempt_count))  //表示preempt_count为真的可能比较大,如果preempt_count为真说明这个时候内核是不允许被抢占的,所以这时返回当前的CPU id是安全的.(goto out返回当前cpu号)
        goto out;
    if (irqs_disabled())
        goto out;

根据处理器编号cpu,将处理器位图的相应位置置为1(其它位为0)
|-----------------------------------------|
|   this_mask = cpumask_of_cpu(this_cpu); |
|-----------------------------------------|

检测该当前进程所在处理器是否可以执行该进程,如果可以则返回1,否则返回0
|-----------------------------------------------------|
|   if (cpus_equal(current->cpus_allowed, this_mask)) |
|       goto out;                                     |
|-----------------------------------------------------|

    if (system_state != SYSTEM_RUNNING)
        goto out;
    preempt_disable();
    if (!printk_ratelimit())
        goto out_enable;
    printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d/n", preempt_count(), current->comm, current->pid);
    print_symbol("caller is %s/n", (long)__builtin_return_address(0));
    dump_stack();

out_enable:
    preempt_enable_no_resched();
out:
    return this_cpu;
}

#define __smp_processor_id() (current_thread_info()->cpu)
task_struct.cpus_allowed    Bitmask of the CPUs that can execute the process
                            可以执行该进程的CPU掩码集

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/kernel_details/archive/2007/01/12/1480917.aspx

 

关于likely()和unlikely()两个函数

举例如下:

likely(a)表示a的值为真的可能性比较大,unlikely(a)表示a的值为假的可能性比较大,这两个函数主要是GCC进行的优化操作,这样在进行if判断的时候能够更好对代码进行组织。

likely(a>b)表示a>b的可能性比较大,unlikely(a>b)表示a>b的可能性比较小。

例如:

if(likely(prev!=next)){

     next->timestap = now;

}

else {

  ...

}

这样表示prev不等于next可能性比较大,这样能够会将可能性更大的代码跟着前面的代码后减少指令跳转带来的损耗。

 

关于preempt_count值的含义

1 相关数据结构

struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
__u32 flags; /* low level flags */
__u32 status; /* thread synchronous flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable,
<0 => BUG */
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
#ifdef CONFIG_X86_32
unsigned long previous_esp; /* ESP of the previous stack in
case of nested (IRQ) stacks
*/
__u8 supervisor_stack[0];
#endif
int uaccess_err;
};
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}
#define preempt_count() (current_thread_info()->preempt_count)

2 以下内容转自:内核抢占

与其他大部分Unix变体和其他大部分的操作系统不同, Linux完整地支持内核抢占。

在不支持内核抢占的内核中,内核代码可以一直执行,到它完成为止。也就是说,调度程序没有办法在一个内核级的任务正在执行的时候重新调度 – 内核中的各任务是协作方式调度的,不具备抢占性。

在2.6版的内核中,内核引入了抢占能力;现在,只要重新调度是安全的,那么内核就可以在任何时间抢占正在执行的任务。

那么,什么时候重新调度才是安全的呢?只要没有持有锁,内核就可以进行抢占。锁是非抢占区域的标志。由于内核是支持SMP的,所以,如果没有持有锁,那么正在执行的代码就是可重新导入的,也就是可以抢占的。

为了支持内核抢占所作的第一处变动就是每个进程的thread_info引入了 preempt_count(thread_info.preempt_count)计数器。该计数器初始值为0,每当使用锁的时候数值加1,释放锁的时候数值减1。当数值为0的时候,内核就可执行抢占。从中断返回内核空间的时候,内核会检查flag和preempt_count的值。如果flag中TIF_NEED_RESCHED被设置,并且preempt_count为0的话,这说明有一个更为重要的任务需要执行并且可以安全地抢占,此时,调度程序就会调度(抢占当前进程)。如果preempt_count不为0,说明当前任务持有锁,所以抢占是不安全的。这时,就会像通常那样直接从中断返回当前执行进程。 如果当前进程所持有的所有的锁都被释放了,那么preemptcount就会重新为0。此时,释放锁的代码会检查need_resched是否被设置。如果是的话,就会调用调度程序。有些内核代码需要允许或禁止内核抢占。

如果内核中的进程被阻塞了,或它显式地调用了schedule(),内核抢占也会显式地发生。这种形式的内核代码从来都是受支持的,因为根本无需额外的逻辑来保证内核可以安全地发生被抢占。如果代码显式的调用了schedule(),那么它应该清楚自己是可以安全地被抢占的。

内核抢占发生在:
当"从中断处理程序"正在执行,且返回内核空间之前
内核代码再一次具有可抢占性的时候
如果内核中的任务显式的调用schedule()
如果内核中的任务阻塞(这同样也会导致调用schedule())

 注:

       current->threadinfo.flags中TIF_NEED_RESCHED为1,表示当前进程需要执行schedule()释放CPU控制权
       current->threadinfo.preemptcount的值不为0,表示当前进程持有锁不能释放CPU控制

权(不能被抢占)

抱歉!评论已关闭.