惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
罗磊的独立博客
博客园 - 【当耐特】
D
Docker
Y
Y Combinator Blog
L
LangChain Blog
博客园 - 三生石上(FineUI控件)
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
F
Fortinet All Blogs
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
B
Blog
The GitHub Blog
The GitHub Blog
腾讯CDC
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
爱范儿
爱范儿
A
About on SuperTechFans
量子位
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

OhYee 博客

小鹏辅助驾驶测评|OhYee 博客 小鹏非支持手机开启自动解锁|OhYee 博客 使用函数计算实现 301 重定向|OhYee 博客 针对 HTML 内容使用 Ant Design 图片弹框|OhYee 博客 博客进程泄露及僵尸进程解决|OhYee 博客 蓝易云服务器体验|OhYee 博客 SSH 调起本地 VSCode|OhYee 博客 【2022 秋招内推】阿里云后端研发工程师|OhYee 博客 使用函数计算获取 IP 地址信息|OhYee 博客 正确获取客户端 IP/HTTP Header 也可能重复|OhYee 博客 评测 Oculus Quest2 及 BigScreen|OhYee 博客 NextJS 热重载保留状态|OhYee 博客 如何优雅地贴 gist 代码|OhYee 博客 Linux 精细化文件权限|OhYee 博客 VSCode 容器开发环境|OhYee 博客 Clash 的不兼容更新排查|OhYee 博客 Zeek 导出 PCAP|OhYee 博客 记一次 ssh 配置问题|OhYee 博客 Git Commit 规范化工具|OhYee 博客 谈谈《星之卡比-探索发现》|OhYee 博客 VSCode 快捷键绑定 Shell 命令|OhYee 博客 ASN.1 语法及 X.509 证书格式解析解析|OhYee 博客 腾讯企业邮箱忽略 MX 记录发信|OhYee 博客 Chrome/Edge 标签组插件|OhYee 博客 【应届内推】阿里云后端研发工程师|OhYee 博客 损坏的 Typecho 备份处理为 JSON|OhYee 博客 VS Code VIM 插件高效使用|OhYee 博客 SSH 正反向代理|OhYee 博客 Let's Encrypt 根证书过期引发的问题|OhYee 博客 OpenWRT 忽略内核依赖|OhYee 博客
Tor子系统——线程模块|OhYee 博客
2020-03-05 · via OhYee 博客

针对 Tor 的 threads 子系统的源码分析

这是一篇最后编辑于 6 年前 的文章,其内容可能与目前实际情况差异较大,请注意甄别

线程模块

Tor笔记目录索引

Tor报错模块位于src/lib/thread/文件夹

Tor 本身运行于一个主线程以及多个工作进程,目前有很多密码学部分被移入了工作线程以提高并行性
其中,互斥锁在src/lib/lock/中定义,线程池、工作队列在src/lib/evloop/中定义,而这里是为跨平台多线程提供的二次封装,输出了跨平台的条件变量和线程

子系统结构

子系统结构定义解释

const subsys_fns_t sys_threads = {
  .name = "threads",
  .supported = true,
  /* Threads is used by logging, which is a diagnostic feature, we want it to
   * init right after low-level error handling and approx time. */
  .level = -95,
  .initialize = subsys_threads_initialize,
};

初始化子系统

根据系统不同,会执行两套不同的流程

在模块文件夹下有include.am文件,这是 m4 的配置文件,在执行./configure时运行,用于选择要编译的文件,在这里会判断系统环境

如果是 Windows ,会引入src/lib/thread/compat_winthreads.c,否则则会使用 src/lib/thread/compat_winthreads.c
(这里实际的逻辑是判断是否为 Windows 环境、是否可以使用 pthread,因此如果在未安装 pthread 的平台,则会出错,不过一般而言 pthread 已经是大部分环境的标配。同时,在compat_winthreads.c中,仍然使用宏定义再次判断了系统环境,这里应该是没必要的

noinst_LIBRARIES += src/lib/libtor-thread.a

if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-thread-testing.a
endif

if THREADS_PTHREADS
threads_impl_source=src/lib/thread/compat_pthreads.c
endif
if THREADS_WIN32
threads_impl_source=src/lib/thread/compat_winthreads.c
endif

# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_thread_a_SOURCES =			\
	src/lib/thread/compat_threads.c			\
	src/lib/thread/numcpus.c			\
	$(threads_impl_source)

src_lib_libtor_thread_testing_a_SOURCES = \
	$(src_lib_libtor_thread_a_SOURCES)
src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)

# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS +=					\
	src/lib/thread/numcpus.h			\
	src/lib/thread/thread_sys.h			\
	src/lib/thread/threads.h

在 Windows 上,线程没有额外配置,单纯将当前线程设置为主线程
而在其他平台上,除去将当前线程设置为主线程外,会先初始化互斥锁,接着则是初始化 pthread 线程类型

由于 tor 主线程会无限处于主循环中,因此主线程不需要等待子线程,所以初始化的会是 detached 线程模型1

条件变量

同时,由于条件变量2在不同平台也存在差异,因此这里也封装了条件变量tor_cond_t以供使用

  • 封装后的条件变量类型:tor_cond_t
  • 初始化条件变量:int tor_cond_init(tor_cond_t*)
  • 阻塞线程:int tor_cond_wait(tor_cond_t *, tor_mutex_t *, const struct timeval *)
  • 发送信号(单个):int tor_cond_signal_one(tor_cond_t *);
  • 发送信号(广播):int tor_cond_signal_all(tor_cond_t *);
typedef struct tor_cond_t {
#ifdef USE_PTHREADS
  pthread_cond_t cond;
#elif defined(USE_WIN32_THREADS)
  HANDLE event;

  CRITICAL_SECTION lock;
  int n_waiting;
  int n_to_wake;
  int generation;
#else
#error no known condition implementation.
#endif /* defined(USE_PTHREADS) || ... */
} tor_cond_t;

tor_cond_t *tor_cond_new(void);
void tor_cond_free_(tor_cond_t *cond);
#define tor_cond_free(c) FREE_AND_NULL(tor_cond_t, tor_cond_free_, (c))
int tor_cond_init(tor_cond_t *cond);
void tor_cond_uninit(tor_cond_t *cond);
int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv);
void tor_cond_signal_one(tor_cond_t *cond);
void tor_cond_signal_all(tor_cond_t *cond);

线程

连条件变量都需要针对平台编译,线程本身自然也需要封装
在使用tor_threadlocal_init()初始化线程后,需要使用tor_threadlocal_set()为线程设置要运行的函数

typedef struct tor_threadlocal_t {
#ifdef _WIN32
  DWORD index;
#else
  pthread_key_t key;
#endif
} tor_threadlocal_t;

int tor_threadlocal_init(tor_threadlocal_t *threadlocal);
void tor_threadlocal_destroy(tor_threadlocal_t *threadlocal);
void *tor_threadlocal_get(tor_threadlocal_t *threadlocal);
void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);

参考资料


  1. pthread 中 join 和 detach ↩︎

  2. pthread 的条件变量 ↩︎