专栏首页原创分享线程源码分析之cancel.c(基于linuxthreads2.0.1)

线程源码分析之cancel.c(基于linuxthreads2.0.1)

cancel.c实现了线程的是否可取消,取消类型,取消线程,设置线程退出时需要执行的函数列表等功能。

/* Thread cancellation */

#include <errno.h>
#include "pthread.h"
#include "internals.h"
#include "restart.h"

/*
 修改线程的可取消属性。有一个取消点
 取消状态分为可取消,不可取消
    不可取消的时候,收到取消信号,忽略
    可取消的时候,收到取消信号的时候,根据取消类型做处理。
      立即处理
      不立刻处理,到下一个取消点,判定线程的状态的取消类型再处理
 */
int pthread_setcancelstate(int state, int * oldstate)
{
  pthread_t self = thread_self();
  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
    return EINVAL;
  // 保存旧的状态
  if (oldstate != NULL) *oldstate = self->p_cancelstate;
  // 设置新的状态
  self->p_cancelstate = state;
  // 判断线程是否被取消了,并且当前被设置成可取消状态,并且是需要马上处理的,则直接退出
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
  return 0;
}
// 见上一个函数
int pthread_setcanceltype(int type, int * oldtype)
{
  pthread_t self = thread_self();
  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
    return EINVAL;
  if (oldtype != NULL) *oldtype = self->p_canceltype;
  self->p_canceltype = type;
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
  return 0;
}
// 给线程发送取消请求,线程收到该信号是否处理,怎么处理取决于线程本身对于取消的相关配置
int pthread_cancel(pthread_t thread)
{
  thread->p_canceled = 1;
  kill(thread->p_pid, PTHREAD_SIG_CANCEL);
  return 0;
}
// 设置一个取消点
void pthread_testcancel(void)
{
  pthread_t self = thread_self();
  // 判断线程是不是已经被取消,并且是可取消的,则退出
  if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)
    pthread_exit(PTHREAD_CANCELED);
}
// 链表中新增一个clean函数
void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
			   void (*routine)(void *), void * arg)
{
  pthread_t self = thread_self();
  buffer->routine = routine;
  buffer->arg = arg;
  // 头插法
  buffer->prev = self->p_cleanup;
  self->p_cleanup = buffer;
}
// 删除一个clean节点,execute判断是否需要执行
void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
			  int execute)
{
  pthread_t self = thread_self();
  if (execute) buffer->routine(buffer->arg);
  self->p_cleanup = buffer->prev;
}
// 新增一个clean节点,保存旧的取消类型,设置新的取消类型为PTHREAD_CANCEL_DEFERRED
void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
				 void (*routine)(void *), void * arg)
{
  pthread_t self = thread_self();
  buffer->routine = routine;
  buffer->arg = arg;
  buffer->canceltype = self->p_canceltype;
  buffer->prev = self->p_cleanup;
  self->p_canceltype = PTHREAD_CANCEL_DEFERRED;
  self->p_cleanup = buffer;
}

// 和上面的函数配套。删除一个clean节点,execute控制是否需要执行删除的这个节点,恢复线程的取消类型,是一个有取消点的函数
void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
				  int execute)
{
  pthread_t self = thread_self();
  if (execute) buffer->routine(buffer->arg);
  self->p_cleanup = buffer->prev;
  self->p_canceltype = buffer->canceltype;
  if (self->p_canceled &&
      self->p_cancelstate == PTHREAD_CANCEL_ENABLE &&
      self->p_canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
    pthread_exit(PTHREAD_CANCELED);
}
// 线程退出的时候(pthread_exit)调用执行clean链表的节点
void __pthread_perform_cleanup(void)
{
  pthread_t self = thread_self();
  struct _pthread_cleanup_buffer * c;
  for (c = self->p_cleanup; c != NULL; c = c->prev) c->routine(c->arg);
}

#ifndef PIC
/* We need a hook to force the cancelation wrappers to be linked in when
   static libpthread is used.  */
extern const int __pthread_provide_wrappers;
static const int * const __pthread_require_wrappers =
  &__pthread_provide_wrappers;
#endif

本文分享自微信公众号 - 编程杂技(theanarkh),作者:theanarkh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 线程源码分析之join.c(基于linuxthreads2.0.1)

    theanarkh
  • nodejs事件循环阶段之poll io

    poll io是nodejs非常重要的一个阶段,文件io、网络io、信号处理等都在这个阶段处理。这也是最复杂的一个阶段。处理逻辑在uv__io_poll这个函数...

    theanarkh
  • 操作系统是如何分加载的

    开机的时候,寄存器cs:ip会强行指向FFFF0H这个地方,这是bios的地址。然后开始执行bios指令,bois指令会把启动盘第一个扇区的数据加载到0x07c...

    theanarkh
  • 理解unittest测试框架(三)——结果处理

    前文说到了测试的核心,用例的处理,这篇文章来说说unittest框架对于测试结果的处理方式。

    点点寒彬
  • 详解文本分类之多通道CNN的理论与实践

    最近在梳理文本分类的各个神经网络算法,特地一个来总结下。接下来将要一个文章一个文章的讲解各个算法的理论与实践。目录暂定为:

    zenRRan
  • Django打造大型企业官网(六)

    zhang_derek
  • 接口测试 | 24 requests + unittest集成你的接口测试

    概述 本文就如何结合requests、unittest进行实例演示,如果你还不了解unittest、PO模型,请翻阅公众号前期发布的unittest专题和PO模...

    苦叶子
  • 接口测试 | 24 requests + unittest集成你的接口测试

    概述 本文就如何结合requests、unittest进行实例演示,如果你还不了解unittest、PO模型,请翻阅公众号前期发布的unittest专题和PO模...

    苦叶子
  • 关于首页倒计时处理一些细节

    促销商品展示的 Cell 是重用的,开始的时候其他栏目是没有赋值的。导致是不能收到已经停止的消息的,自然也就没办法从列表里面进行移除

    君赏
  • 利用Python让你的命令行像坤坤一样会打篮球

    承接上文,作为一个经常逛b站的肥宅,近期b站上除了流行"品如”素材的视频,更多的莫过于蔡xx打球视频的了,有模仿的,有对比的,有手绘的,更过分的是竟然有人在命令...

    统计学家

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动