tcp拥塞控制状态机在linux内核源码的什么位置

tcp拥塞控制状态机在linux内核源码的什么位置,第1张

公平性

公平性是在发生拥塞时各

源端(或同一源端建立的不同TCP连接或UDP数据报)能公平地共享同一网络资源(如带宽、缓存等)。处于相同级别的源端应该得到相同数量的网络资源。产

生公平性的根本原因在于拥塞发生必然导致数据包丢失,而数据包丢失会导致各数据流之间为争抢有限的网络资源发生竞争,争抢能力弱的数据流将受到更多损害。

因此,没有拥塞,也就没有公平性问题。

TCP层上的公平性问题表现在两方面:

(1)

面向连接的TCP和无连接的UDP在拥塞发生时对拥塞指示的不同反应和处理,导致对网络资源的不公平使用问题。在拥塞发生时,有拥塞控制反应机制的TCP

数据流会按拥塞控制步骤进入拥塞避免阶段,从而主动减小发送入网络的数据量。但对无连接的数据报UDP,由于没有端到端的拥塞控制机制,即使网络发出了拥

塞指示(如数据包丢失、收到重复ACK等),UDP也不会像TCP那样减少向网络发送的数据量。结果遵守拥塞控制的TCP数据流得到的网络资源越来越少,

没有拥塞控制的UDP则会得到越来越多的网络资源,这就导致了网络资源在各源端分配的严重不公平。

网络资源分配的不公平反

过来会加重拥塞,甚至可能导致拥塞崩溃。因此如何判断在拥塞发生时各个数据流是否严格遵守TCP拥塞控制,以及如何“惩罚”不遵守拥塞控制协议的行为,成

了目前研究拥塞控制的一个热点。在传输层解决拥塞控制的公平性问题的根本方法是全面使用端到端的拥塞控制机制。

(2) 一些TCP连接之间也存在公平性问题。产生问题的原因在于一些TCP在拥塞前使用了大窗口尺寸,或者它们的RTT较小,或者数据包比其他TCP大,这样它们也会多占带宽。

RTT不公平性

AIMD拥塞窗口更新策

略也存在一些缺陷,和式增加策略使发送方发送数据流的拥塞窗口在一个往返时延(RTT)内增加了一个数据包的大小,因此,当不同的数据流对网络瓶颈带宽进

行竞争时,具有较小RTT的TCP数据流的拥塞窗口增加速率将会快于具有大RTT的TCP数据流,从而将会占有更多的网络带宽资源。

附加说明

中美之间的线路质量不是很好,rtt较长且时常丢包。TCP协议是成也丢包,败也丢包;TCP的设计目的是解决不可靠线路上可靠传输的问题,即为了解决丢包,但丢包却使TCP传输速度大幅下降。HTTP协议在传输层使用的是TCP协议,所以网页下载的速度就取决于TCP单线程下载的速度(因为网页就是单线程下载的)。

丢包使得TCP传输速度大幅下降的主要原因是丢包重传机制,控制这一机制的就是TCP拥塞控制算法。

Linux内核中提供了若干套TCP拥塞控制算法,已加载进内核的可以通过内核参数net.ipv4.tcp_available_congestion_control看到。

Vegas

1994

年,Brakmo提出了一种新的拥塞控制机制TCP

Vegas,从另外的一个角度来进行拥塞控制。从前面可以看到,TCP的拥塞控制是基于丢包的,一旦出现丢包,于是调整拥塞窗口,然而由于丢包不一定是由

于网络进入了拥塞,但是由于RTT值与网络运行情况有比较密切的关系,于是TCP

Vegas利用RTT值的改变来判断网络是否拥塞,从而调整拥塞控制窗口。如果发现RTT在增大,Vegas就认为网络正在发生拥塞,于是开始减小拥塞窗

口,如果RTT变小,Vegas认为网络拥塞正在逐步解除,于是再次增加拥塞窗口。由于Vegas不是利用丢包来判断网络可用带宽,而是利用RTT变化来判断,因而可以更精确的探测网络的可用带宽,从而效率更好。然而Vegas的有一个缺陷,并且可以说致命的,最终影响TCP

Vegas并没有在互联网上大规模使用。这个问题就是采用TCP Vegas的流的带宽竞争力不及未使用TCP Vegas的流,

这是因为网络中路由器只要缓冲了数据,就会造成RTT的变大,如果缓冲区没有溢出的话,并不会发生拥塞,但是由于缓存数据就会导致处理时延,从而RTT变

大,特别是在带宽比较小的网络上,只要一开始传输数据,RTT就会急剧增大,这个在无线网络上特别明显。在这种情况下,TCP

Vegas降低自己的拥塞窗口,但是只要没有丢包的话,从上面看到标准的TCP是不会降低自己的窗口的,于是两者开始不公平,再这样循环下去,TCP

Vegas的效率就非常低了。其实如果所有的TCP都采用Vegas拥塞控制方式的话,流之间的公平性会更好,竞争能力并不是Vegas算法本身的问题。

适用环境:很难在互联网上大规模适用(带宽竞争力低)

2. Reno

Reno是目前应用最广泛且较为成熟的算法。该算法所包含的慢启动、拥塞避免和快速重传、快速恢复机制,是现有的众多算法的基础。从Reno运行机制中很容易看出,为了维持一个动态平衡,必须周期性地产生一定量的丢失,再加上AIMD机制--减少快,增长慢,尤其是在大窗口环境下,由于一个数据报的丢失所带来的窗口缩小要花费很长的时间来恢复,这样,带宽利用率不可能很高且随着网络的链路带宽不断提升,这种弊端将越来越明显。公平性方面,根据统计数据,Reno的公平性还是得到了相当的肯定,它能够在较大的网络范围内理想地维持公平性原则。

Reno算法以其简单、有效和鲁棒性成为主流,被广泛的采用。

但是它不能有效的处理多个分组从同一个数据窗口丢失的情况。这一问题在New Reno算法中得到解决。

基于丢包反馈的协议

近几年来,随着高带宽延时网络(High Bandwidth-Delay product network)的普及,针对提高TCP带宽利用率这一点上,又涌现出许多新的基于丢包反馈的TCP协议改进,这其中包括HSTCP、STCP、BIC-TCP、CUBIC和H-TCP。

总的来说,基于丢包反馈

的协议是一种被动式的拥塞控制机制,其依据网络中的丢包事件来做网络拥塞判断。即便网络中的负载很高时,只要没有产生拥塞丢包,协议就不会主动降低自己的

发送速度。这种协议可以最大程度的利用网络剩余带宽,提高吞吐量。然而,由于基于丢包反馈协议在网络近饱和状态下所表现出来的侵略性,一方面大大提高了网络的带宽利用率;但另一方面,对于基于丢包反馈的拥塞控制协议来说,大大提高网络利用率同时意味着下一次拥塞丢包事件为期不远了,所以这些协议在提高网络带宽利用率的同时也间接加大了网络的丢包率,造成整个网络的抖动性加剧。

友好性

BIC-TCP、

HSTCP、STCP等基于丢包反馈的协议在大大提高了自身吞吐率的同时,也严重影响了Reno流的吞吐率。基于丢包反馈的协议产生如此低劣的TCP友好

性的组要原因在于这些协议算法本身的侵略性拥塞窗口管理机制,这些协议通常认为网络只要没有产生丢包就一定存在多余的带宽,从而不断提高自己的发送速率。

其发送速率从时间的宏观角度上来看呈现出一种凹形的发展趋势,越接近网络带宽的峰值发送速率增长得越快。这不仅带来了大量拥塞丢包,同时也恶意吞并了网络

中其它共存流的带宽资源,造成整个网络的公平性下降。

3. HSTCP(High Speed TCP)

HSTCP(高速传输控制协议)是高速网络中基于AIMD(加性增长和乘性减少)的一种新的拥塞控制算法,它能在高速度和大时延的网络中更有效地提高网络的吞吐率。它通过对标准TCP拥塞避免算法的增加和减少参数进行修改,从而实现了窗口的快速增长和慢速减少,使得窗口保持在一个足够大的范围,以充分利用带宽,它在高速网络中能够获得比TCP

Reno高得多的带宽,但是它存在很严重的RTT不公平性。公平性指共享同一网络瓶颈的多个流之间占有的网络资源相等。

TCP发送端通过网络所期望的丢包率来动态调整HSTCP拥塞窗口的增量函数。

拥塞避免时的窗口增长方式: cwnd = cwnd + a(cwnd) / cwnd

丢包后窗口下降方式:cwnd = (1-b(cwnd))*cwnd

其中,a(cwnd)和

b(cwnd)为两个函数,在标准TCP中,a(cwnd)=1,b(cwnd)=0.5,为了达到TCP的友好性,在窗口较低的情况下,也就是说在非

BDP的网络环境下,HSTCP采用的是和标准TCP相同的a和b来保证两者之间的友好性。当窗口较大时(临界值LowWindow=38),采取新的a

和b来达到高吞吐的要求。具体可以看RFC3649文档。

4. westwood

无线网络中,在大量研究的基础上发现tcpwestwood是一种较理想的算法,它的主要思想是通过在发送端持续不断的检测ack的到达速率来进行带宽估计,当拥塞发生时用带宽估计值来调整拥塞窗口和慢启动阈值,采用aiad(additive increase and

adaptive decrease)拥塞控制机制。它不仅提高了无线网络的吞吐量,而且具有良好的公平性和与现行网络的互 *** 作性。存在的问题是不能很好的区分传输过程中的拥塞丢包和无线丢包,导致拥塞机制频繁调用。

5. H-TCP

高性能网络中综合表现比较优秀的算法是:h-tcp,但它有rtt不公平性和低带宽不友好性等问题。

6. BIC-TCP

BIC-TCP的缺点:首先就是抢占性较强,BIC-TCP的增长函数在小链路带宽时延短的情况下比起标准的TCP来抢占性强,它在探测阶段相当于是重新启动一个慢启动算法,而TCP在处于稳定后窗口就是一直是线性增长的,不会再次执行慢启动的过程。其次,BIC-TCP的的窗口控制阶段分为binary

search increase、max probing,然后还有Smax和Smin的区分,这几个值增加了算法上的实现难度,同时也对协议性能的分析模型增加了复杂度。在低RTT网络 和低速环境中,BIC可能会过于“积极”,因而人们对BIC进行了进一步的改进,即CUBIC。是Linux在采用CUBIC之前的默认算法。

7. CUBIC

CUBIC在设计上简化了BIC-TCP的窗口调整算法,

在BIC-TCP的窗口调整中会出现一个凹和凸(这里的凹和凸指的是数学意义上的凹和凸,凹函数/凸函数)的增长曲线,CUBIC使用了一个三次函数(即

一个立方函数),在三次函数曲线中同样存在一个凹和凸的部分,该曲线形状和BIC-TCP的曲线图十分相似,于是该部分取代BIC-TCP的增长曲线。另

外,CUBIC中最关键的点在于它的窗口增长函数仅仅取决于连续的两次拥塞事件的时间间隔值,从而窗口增长完全独立于网络的时延RTT,之前讲述过的HSTCP存在严重的RTT不公平性,而CUBIC的RTT独立性质使得CUBIC能够在多条共享瓶颈链路的TCP连接之间保持良好的RTT公平性。

CUBIC is a congestion control protocol for TCP (transmission control protocol) and thecurrent default TCP algorithm in Linux.

The protocol modifies the linear window

growth function of existing TCP standards to be a cubic function in

order to improve the scalability of TCP over fast and long distance

networks. It also achieves more equitable bandwidth allocations among

flows with different RTTs (round trip times) by making

the window growth to be independent of RTT – thus those flows grow

their congestion window at the same rate. During steady state, CUBIC

increases the window size aggressively when the window is far from the

saturation point, and the slowly when it is close

to the saturation point.This feature allows

CUBIC to be very scalable when the bandwidth and delay product of the

network is large, and at the same time, be highly stable and also fair

to standard TCP flows.

8. STCP

STCP,Scalable tcp。

STCP算法是由 Tom Kelly于 2003年提出的 ,通过修改 TCP的窗口增加和减少参数来调整发送窗口大小 ,以适应高速网络的环境。该算法具有很高的链路利用率和稳定性,但该机制窗口增加和 RTT成反比 ,在一定的程度上存在着

RTT不公平现象 ,而且和传统 TCP流共存时 ,过分占用带宽 ,其 TCP友好性也较差。

 mutex相关的函数并不是linux kernel实现的,而是glibc实现的,源码位于nptl目录下。

http://ftp.gnu.org/pub/gnu/glibc/glibc-2.3.5.tar.gz

首先说数据结构:

typedef union

{

  struct

  {

    int __lock

    unsigned int __count

    int __owner

    unsigned int __nusers

    /* KIND must stay at this position in the structure to maintain

       binary compatibility.  */

    int __kind

    int __spins

  } __data

  char __size[__SIZEOF_PTHREAD_MUTEX_T]

  long int __align

} pthread_mutex_t

 int __lock  资源竞争引用计数

 int __kind锁类型,init 函数中mutexattr 参数传递,该参数可以为NULL,一般为 PTHREAD_MUTEX_NORMAL

结构体其他元素暂时不了解,以后更新。

/*nptl/pthread_mutex_init.c*/

int

__pthread_mutex_init (mutex, mutexattr)

     pthread_mutex_t *mutex

     const pthread_mutexattr_t *mutexattr

{

  const struct pthread_mutexattr *imutexattr

  assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T)

  imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr

  /* Clear the whole variable.  */

  memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T)

  /* Copy the values from the attribute.  */

  mutex->__data.__kind = imutexattr->mutexkind &~0x80000000

  /* Default values: mutex not used yet.  */

  // mutex->__count = 0        already done by memset

  // mutex->__owner = 0        already done by memset

  // mutex->__nusers = 0        already done by memset

  // mutex->__spins = 0        already done by memset

  return 0

}

init函数就比较简单了,将mutex结构体清零,设置结构体中__kind属性。

/*nptl/pthread_mutex_lock.c*/

int

__pthread_mutex_lock (mutex)

     pthread_mutex_t *mutex

{

  assert (sizeof (mutex->__size) >= sizeof (mutex->__data))

  pid_t id = THREAD_GETMEM (THREAD_SELF, tid)

  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))

    {

     …

    default:

      /* Correct code cannot set any other type.  */

    case PTHREAD_MUTEX_TIMED_NP:

    simple:

      /* Normal mutex.  */

      LLL_MUTEX_LOCK (mutex->__data.__lock)

      break

  …

  }

  /* Record the ownership.  */

  assert (mutex->__data.__owner == 0)

  mutex->__data.__owner = id

#ifndef NO_INCR

  ++mutex->__data.__nusers

#endif

  return 0

}

该函数主要是调用LLL_MUTEX_LOCK, 省略部分为根据mutex结构体__kind属性不同值做些处理。

宏定义函数LLL_MUTEX_LOCK最终调用,将结构体mutex的__lock属性作为参数传递进来

#define __lll_mutex_lock(futex)                                                \

  ((void) ({                                                                \

    int *__futex = (futex)                                                \

    if (atomic_compare_and_exchange_bool_acq (__futex, 1, 0) != 0)        \

      __lll_lock_wait (__futex)                                        \

  }))

atomic_compare_and_exchange_bool_acq (__futex, 1, 0)宏定义为:

#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \

  ({ __typeof (mem) __gmemp = (mem)                                      \

     __typeof (*mem) __gnewval = (newval)                              \

      \

     *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1})

这个宏实现的功能是:

如果mem的值等于oldval,则把newval赋值给mem,放回0,否则不做任何处理,返回1.

由此可以看出,当mutex锁限制的资源没有竞争时,__lock 属性被置为1,并返回0,不会调用__lll_lock_wait (__futex)当存在竞争时,再次调用lock函数,该宏不做任何处理,返回1,调用__lll_lock_wait (__futex)

void

__lll_lock_wait (int *futex)

{

  do

    {

      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1)

      if (oldval != 0)

lll_futex_wait (futex, 2)

    }

  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)

}

atomic_compare_and_exchange_val_acq (futex, 2, 1)宏定义:

/* The only basic operation needed is compare and exchange.  */

#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \

  ({ __typeof (mem) __gmemp = (mem)                                      \

     __typeof (*mem) __gret = *__gmemp                                      \

     __typeof (*mem) __gnewval = (newval)                              \

      \

     if (__gret == (oldval))                                              \

       *__gmemp = __gnewval                                              \

     __gret})

这个宏实现的功能是,当mem等于oldval时,将mem置为newval,始终返回mem原始值。

此时,futex等于1,futex将被置为2,并且返回1. 进而调用

lll_futex_wait (futex, 2)

#define lll_futex_timed_wait(ftx, val, timespec)                        \

({                                                                        \

   DO_INLINE_SYSCALL(futex, 4, (long) (ftx), FUTEX_WAIT, (int) (val),        \

     (long) (timespec))                                \

   _r10 == -1 ? -_retval : _retval                                        \

})

该宏对于不同的平台架构会用不同的实现,采用汇编语言实现系统调用。不过确定的是调用了Linux kernel的futex系统调用。

futex在linux kernel的实现位于:kernel/futex.c

SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,

struct timespec __user *, utime, u32 __user *, uaddr2,

u32, val3)

{

struct timespec ts

ktime_t t, *tp = NULL

u32 val2 = 0

int cmd = op &FUTEX_CMD_MASK

if (utime &&(cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||

      cmd == FUTEX_WAIT_BITSET ||

      cmd == FUTEX_WAIT_REQUEUE_PI)) {

if (copy_from_user(&ts, utime, sizeof(ts)) != 0)

return -EFAULT

if (!timespec_valid(&ts))

return -EINVAL

t = timespec_to_ktime(ts)

if (cmd == FUTEX_WAIT)

t = ktime_add_safe(ktime_get(), t)

tp = &t

}

/*

 * requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*.

 * number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP.

 */

if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||

    cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)

val2 = (u32) (unsigned long) utime

return do_futex(uaddr, op, val, tp, uaddr2, val2, val3)

}

futex具有六个形参,pthread_mutex_lock最终只关注了前四个。futex函数对参数进行判断和转化之后,直接调用do_futex。

long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,

u32 __user *uaddr2, u32 val2, u32 val3)

{

int clockrt, ret = -ENOSYS

int cmd = op &FUTEX_CMD_MASK

int fshared = 0

if (!(op &FUTEX_PRIVATE_FLAG))

fshared = 1

clockrt = op &FUTEX_CLOCK_REALTIME

if (clockrt &&cmd != FUTEX_WAIT_BITSET &&cmd != FUTEX_WAIT_REQUEUE_PI)

return -ENOSYS

switch (cmd) {

case FUTEX_WAIT:

val3 = FUTEX_BITSET_MATCH_ANY

case FUTEX_WAIT_BITSET:

ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt)

break

         …

default:

ret = -ENOSYS

}

return ret

}

省略部分为对其他cmd的处理,pthread_mutex_lock函数最终传入的cmd参数为FUTEX_WAIT,所以在此只关注此分之,分析futex_wait函数的实现。

static int futex_wait(u32 __user *uaddr, int fshared,

      u32 val, ktime_t *abs_time, u32 bitset, int clockrt)

{

struct hrtimer_sleeper timeout, *to = NULL

struct restart_block *restart

struct futex_hash_bucket *hb

struct futex_q q

int ret

           … … //delete parameters check and convertion

retry:

/* Prepare to wait on uaddr. */

ret = futex_wait_setup(uaddr, val, fshared, &q, &hb)

if (ret)

goto out

/* queue_me and wait for wakeup, timeout, or a signal. */

futex_wait_queue_me(hb, &q, to)

… … //other handlers

return ret

}

futex_wait_setup 将线程放进休眠队列中,

futex_wait_queue_me(hb, &q, to)将本线程休眠,等待唤醒。

唤醒后,__lll_lock_wait函数中的while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)语句将被执行,由于此时futex在pthread_mutex_unlock中置为0,所以atomic_compare_and_exchange_bool_acq (futex, 2, 0)语句将futex置为2,返回0. 退出循环,访问用户控件的临界资源。

/*nptl/pthread_mutex_unlock.c*/

int

internal_function attribute_hidden

__pthread_mutex_unlock_usercnt (mutex, decr)

     pthread_mutex_t *mutex

     int decr

{

  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))

    {

   … …

    default:

      /* Correct code cannot set any other type.  */

    case PTHREAD_MUTEX_TIMED_NP:

    case PTHREAD_MUTEX_ADAPTIVE_NP:

      /* Normal mutex.  Nothing special to do.  */

      break

    }

  /* Always reset the owner field.  */

  mutex->__data.__owner = 0

  if (decr)

    /* One less user.  */

    --mutex->__data.__nusers

  /* Unlock.  */

  lll_mutex_unlock (mutex->__data.__lock)

  return 0

}

省略部分是针对不同的__kind属性值做的一些处理,最终调用 lll_mutex_unlock。

该宏函数最终的定义为:

#define __lll_mutex_unlock(futex)                        \

  ((void) ({                                                \

    int *__futex = (futex)                                \

    int __val = atomic_exchange_rel (__futex, 0)        \

\

    if (__builtin_expect (__val >1, 0))                \

      lll_futex_wake (__futex, 1)                        \

  }))

atomic_exchange_rel (__futex, 0)宏为:

#define atomic_exchange_rel(mem, value) \

  (__sync_synchronize (), __sync_lock_test_and_set (mem, value))

实现功能为:将mem设置为value,返回原始mem值。

__builtin_expect (__val >1, 0) 是编译器优化语句,告诉编译器期望值,也就是大多数情况下__val >1 ?是0,其逻辑判断依然为if(__val >1)为真的话执行 lll_futex_wake。

现在分析,在资源没有被竞争的情况下,__futex 为1,那么返回值__val则为1,那么 lll_futex_wake (__futex, 1)        不会被执行,不产生系统调用。 当资源产生竞争的情况时,根据对pthread_mutex_lock 函数的分析,__futex为2, __val则为2,执行 lll_futex_wake (__futex, 1)从而唤醒等在临界资源的线程。

lll_futex_wake (__futex, 1)最终会调动同一个系统调用,即futex, 只是传递的cmd参数为FUTEX_WAKE。

在linux kernel的futex实现中,调用

static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)

{

struct futex_hash_bucket *hb

struct futex_q *this, *next

struct plist_head *head

union futex_key key = FUTEX_KEY_INIT

int ret

if (!bitset)

return -EINVAL

ret = get_futex_key(uaddr, fshared, &key)

if (unlikely(ret != 0))

goto out

hb = hash_futex(&key)

spin_lock(&hb->lock)

head = &hb->chain

plist_for_each_entry_safe(this, next, head, list) {

if (match_futex (&this->key, &key)) {

if (this->pi_state || this->rt_waiter) {

ret = -EINVAL

break

}

/* Check if one of the bits is set in both bitsets */

if (!(this->bitset &bitset))

continue

wake_futex(this)

if (++ret >= nr_wake)

break

}

}

spin_unlock(&hb->lock)

put_futex_key(fshared, &key)

out:

return ret

}

该函数遍历在该mutex上休眠的所有线程,调用wake_futex进行唤醒,

static void wake_futex(struct futex_q *q)

{

struct task_struct *p = q->task

/*

 * We set q->lock_ptr = NULL _before_ we wake up the task. If

 * a non futex wake up happens on another CPU then the task

 * might exit and p would dereference a non existing task

 * struct. Prevent this by holding a reference on p across the

 * wake up.

 */

get_task_struct(p)

plist_del(&q->list, &q->list.plist)

/*

 * The waiting task can free the futex_q as soon as

 * q->lock_ptr = NULL is written, without taking any locks. A

 * memory barrier is required here to prevent the following

 * store to lock_ptr from getting ahead of the plist_del.

 */

smp_wmb()

q->lock_ptr = NULL

wake_up_state(p, TASK_NORMAL)

put_task_struct(p)

}

wake_up_state(p, TASK_NORMAL)  的实现位于kernel/sched.c中,属于linux进程调度的技术。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7554200.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-07
下一篇 2023-04-07

发表评论

登录后才能评论

评论列表(0条)

保存