PPP LWIP中断安全 线程安全

 在做ppp驱动3G/4G模块时,用的LWIP协议栈,循环接收处理串口数据时,会调用这2个函数中的一个
pppos_input();
pppos_input_tcpip()

看下面这段话,我理解的意思是,pppos_input_tcpip()是线程安全的,可以随便调用, 但是也不要从串口收到一个字节就调用1 次, 而pppos_input()是线程不安全的,如果在运行pppos_input()的时候,不能调用NEVER call pppos_connect(), pppos_listen() and ppp_free() ,这些函数。




PPPoS input path (raw API, IRQ safe API, TCPIP API)
=====================================================

Received data on serial port should be sent to lwIP using the pppos_input()
function or the pppos_input_tcpip() function.

If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
is not IRQ safe and then *MUST* only be called inside your main loop.

Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
safe and can be safely called from an interrupt context, using that is going
to reduce your need of buffer if pppos_input() is called byte after byte in
your rx serial interrupt.

if NO_SYS is 0, the thread safe way outside an interrupt context is to use
the pppos_input_tcpip() function to pass input data to the lwIP core thread
using the TCPIP API. This is thread safe in all cases but you should avoid
passing data byte after byte because it uses heavy locking (mailbox) and it
allocates pbuf, better fill them !

if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
from an RX thread, however pppos_input() is not thread safe by itself. You can
do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
really know what you are doing, your move ;-)


下面只分析pppos_input_tcpip,因为这个简单,
err_t
pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
{
  struct pbuf *p;
  err_t err;

  p = pbuf_alloc(PBUF_RAW, l, PBUF_POOL);
  if (!p) {
    return ERR_MEM;
  }
  pbuf_take(p, s, l);

  err = tcpip_inpkt(p, ppp_netif(ppp), pppos_input_sys);
  if (err != ERR_OK) {
     pbuf_free(p);
  }
  return err;
}

上面可以看出来,它是怎么实现线程安全的,当pppos_input_tcpip收到数据时,它直接分配1个pbuf,把数据放在pbuf中,然后提交处理,这种办法的缺点也是很明显的,数据每次收到的串口数据较少时,会频率的分配内存释放内存,严重浪费了CPU资源, 它是以占用内存,占用CPU资源为代价来实现线程安全的。

pppos_input就不分析了,大概就是直接分析pppos串口数据,剔除escaped转义字符,直接给上层(TCPIP)提交ether报文,我认为这样处理效率高多了。

注:后来看程序发现

#if !NO_SYS && !PPP_INPROC_IRQ_SAFE

pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)

{}

#endif

也就是使用RTOS且,没有定义PPP_INPROC_IRQ_SAFE时,才会定义pppos_input_tcpip()函数。

 

#if PPP_INPROC_IRQ_SAFE

          if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) {

            PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", ppp->netif->num));

            pbuf_free(inp);

            LINK_STATS_INC(link.drop);

            MIB2_STATS_NETIF_INC(ppp->netif, ifindiscards);

          }

#else /* PPP_INPROC_IRQ_SAFE */

          ppp_input(ppp, inp);

#endif /* PPP_INPROC_IRQ_SAFE */

/*下面转自百度百科*/

可重入函数特征: [2] 

①不为连续的调用持有静态数据; [2] 

②不返回指向静态数据的指针;所有数据都由函数的调用者提供; [2] 

③使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据; [2] 

④如果必须访问全局变量,记住利用互斥信号量来保护全局变量; [2] 

⑤绝不调用任何不可重入函数。 [2] 

不可重入函数特征: [2] 

①函数中使用了静态变量,无论是全局静态变量还是局部静态变量; [2] 

②函数返回静态变量; [2] 

③函数中调用了不可重入函数; [2] 

④函数体内使用了静态的数据结构; [2] 

⑤函数体内调用了malloc()或者free()函数; [2] 

⑥函数体内调用了其他标准I/O函数; [2] 

⑦函数是singleton中的成员函数而且使用了未采用线程独立存储的成员变量。 [2] 

总的来说,如果一个函数在重入条件下使用了未受保护的共享资源,那么它是不可重入的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值