小编QnA*_*QnA的帖子

哪个 Linux 内核函数创建了“进程 0”?

我试图更多地了解process 0,例如,它是否具有内存描述符(非NULL task_struct->mm字段),以及它与交换或空闲进程有什么关系。在我看来,在启动 cpu 上创建了一个“进程 0”,然后为每个其他 cpu 创建了一个空闲线程idle_threads_init,但我没有找到第一个(我假设是process 0)的创建位置.

更新

根据tychen 引用的live book,这是我对process 0(x86_64)的最新理解,有人可以确认/反驳以下项目吗?

  1. 一个init_task类型化的task_struct定义是静态的,随着任务的内核堆栈init_task.stack = init_stack,内存描述符init_task.mm=NULLinit_task.active_mm=&init_mm,其中堆栈区init_stackmm_struct init_mm都静态定义。
  2. 只有active_mm非空的事实意味着process 0是一个内核进程。还有,init_task.flags=PF_KTHREAD
  3. 不长的未压缩的内核映像开始执行后,开机CPU开始使用init_stack的内核堆栈。这使得current宏有意义(自机器启动以来第一次),这使得fork()可能。在这一点之后,内核实际上运行 inprocess 0的上下文。
  4. start_kernel-> arch_call_rest_init-> rest_init,在这个函数内部,process 1&2是分叉的。在kernel_init为 调度的函数中,为每个其他逻辑 CPU 创建process …

c boot x86 assembly linux-kernel

8
推荐指数
1
解决办法
425
查看次数

Linux 内核 flush_write_buffers() 如何在 x86 上工作?

以下代码来自include/asm-i386/io.h,并且是从调用的dma_map_single()。我的理解是flush_write_buffers()应该在为 DMA 映射内存之前刷新 CPU 内存缓存。但是这个汇编代码是如何刷新 CPU 缓存的呢?

static inline void flush_write_buffers(void)
{
    __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory");
}
Run Code Online (Sandbox Code Playgroud)

c x86 assembly linux-kernel dma

5
推荐指数
2
解决办法
276
查看次数

GCC 警告 gettid() 系统调用包装器,glibc 2.30-8

手册页SO post#1 / SO post#2都表明gettid()是在 glibc 2.30 中实现的。我想我正在使用GLIBC 2.30-8,根据ldd --version,但gcc仍然抱怨 -警告:函数'gettid'的隐式声明;您指的是 'getgid' 吗?[-Wimplicit-function-declaration]。我可以忽略警告,程序运行良好。

我尝试使用的标题gettid()<sys/types.h>,遵循手册页。我错过了什么?

syscall(SYS_gettid)使用标头调用<sys/syscall.h>不会触发gcc.

c linux glibc system-calls

5
推荐指数
2
解决办法
792
查看次数

NGINX + Flask,没有 Gunicorn?

我对此很陌生,但是通过将 gunicorn 与flask/werkzeug 的代码进行比较,我无法理解在nginx 和flask 之间插入gunicorn 的真正好处。想得到一些专家的意见。

就我目前所了解的而言,归结为将 gunicorn 与 werkzeug 的开发服务器进行比较。简而言之,我不明白为什么 werkzeug 的服务器被称为开发服务器,而 gunicorn 被认为是生产就绪的。我能想到的选择gunicorn而不是werkzeug的论点:

  1. 表现。Gunicorn 基于 prefork 模型,而 werkzeug 可以为每个请求动态分离线程或进程。但是史蒂文斯在他的 UNP 书中有一个比较,而 prefork 在他的测试中并不是一个明显的赢家。在 linux 上分拆一个线程(而不是进程)应该相当便宜,不需要处理预分叉的进程池。所以对于 CPU 绑定的服务,python GIL 使得 werkzeug 的线程模型没有那么吸引人,但是对于 IO 绑定的服务,werkzeug 应该够好吗?
  2. Gunicorn 支持 gevent/eventlet/tornado,而 werkzeug 不支持。但是由于 asyncio 正在成为 Python 3 的原生库,这些绿色线程库似乎不那么重要了?
  3. 安全?再说一次,我不是这方面的专家,但 nginx 似乎已经是一个很好的捍卫者了?此外,与werkzeug 的开发服务器相比,gunicorn 在这方面似乎没有提供额外的保护。
  4. SSL。Flask 和 werkzeug 服务器似乎无法处理这个问题。但是nginx已经可以处理了,所以flask不需要吗?
  5. Unix 套接字。Werkzeug 的服务器似乎不处理 unix 套接字。因此,如果 nginx 需要使用 unix 套接字将流量转发到后端,无论是因为这是唯一的方法还是因为它是最有效的方法,那么对于 gunicorn 来说似乎是一个很好的论据。

上述理由是否成立?其他原因是什么?

顺便说一句,我已经阅读了SO post 1SO post 2,但它们似乎还没有完全回答我的问题。

python wsgi nginx flask server

5
推荐指数
1
解决办法
1143
查看次数

putenv()/setenv() 如何在不移动整个用户堆栈的情况下工作?

我在这里阅读了几篇文章,但仍然对如何setenv()工作感到困惑:

我的理解是,环境变量作为一堆“foo=bar\0”字符串连续存储在用户堆栈的底部,然后有一个envp[]指向这些字符串的指针数组,也靠近堆栈的底部用户堆栈。用户堆栈在这些字节之上增长,这意味着向字符串区域或指针数组添加更多内容并不简单。setenv()那么,如果设置了新变量(需要添加一个元素envp[]),或者更改了变量但新值字符串比旧值字符串长(使得就地修改不可能),而不需要(几乎)移动变量,那么如何工作?整个用户堆栈为新人腾出空间?

一个有点相关的问题是,是否bash保留本地设置变量的内部列表,并且当用户使用export本地设置变量时,bash只需将其从本地管理列表中删除,并将其添加到上述堆栈字符串区域的底部并将其指针插入到指针数组envp[],以便其子进程自动继承导出的变量?

c linux process environment-variables linux-kernel

5
推荐指数
1
解决办法
474
查看次数

c ++ 20范围库,如何使条件运算符工作?

为标题道歉,如果我知道如何更好地表达它,那么谷歌可能已经帮助了我......

我想要一个对象 Y,它代表容器 X 的视图,这样当我迭代 Y 时,它是 X 的向前或向后迭代。我想在不复制数据的情况下进行,因此新ranges库出现记在心里。

std::vector x{};
auto z = some_condition ? x : (x | std::views::reverse);
Run Code Online (Sandbox Code Playgroud)

显然,x和的类型(x|...)是不同的。我怎样才能使它们一致?

编辑:刚刚发现10 年前提出的以下问题,我想我想知道的是,ranges现在让事情变得更容易了吗?由于该解决方案仍然需要将 for 循环逻辑放入单独的函数或 lambda 中。

c++ c++20 std-ranges

5
推荐指数
1
解决办法
146
查看次数

libdrm 是否通过 ioctl() 与内核 DRM/显卡对话?

这可能是一个愚蠢的问题,因为我对这个主题不太了解...似乎用户应用程序可以直接与 GPU 对话来渲染图像,例如使用 OpenGL,通过 mesa 和 libdrm,其中 libdrm 是各种 ioctl() 调用的包装器,如下所示。这是否意味着对于 3D 游戏的每个新帧,游戏应用程序都需要调用 ioctl() 一次(如果需要达到 KMS,甚至可能调用两次)?这听起来像是大量的用户-内核空间障碍跨越(想想 120 fps 的游戏)。

c graphics ioctl drm linux-kernel

3
推荐指数
1
解决办法
1660
查看次数

linux内核系统调用服务例程的源代码在哪里?

我对系统调用(高级)工作流程的理解是:

  1. 用户调用 libc 包装器
  2. 包装器将系统调用号和参数放在正确的位置、寄存器或堆栈中
  3. 包装器执行 syscall 或 int 0x80 指令
  4. 内核中断处理程序调用 sys_xxx() 服务例程

如果是这样,那么内核源代码中应该有一堆 sys_xxx() 函数。例如,对于read(),在内核 2.6 代码中,我找到了sys_read。然而,在内核 5.4 代码中,我没有找到这样的服务例程代码,我发现的唯一sys_read就像是 libc 包装器的替代品。所以我很困惑..

一个相关的问题 - 内核将实现放在 sys_xxx() 中的原因是内核空间也可以调用这些函数,对吗?

c system-calls linux-kernel

2
推荐指数
1
解决办法
432
查看次数

TCP FIN 字节值?

我的问题实际上分为两部分:

从发送者的角度来看,

  1. 除了 TCP 标头 FIN 标志之外,TCP 层是否真的在流中注入(或者更像附加,因为它应该位于流的末尾)一个人工字节,这意味着该字节是 TCP 有效负载的一部分?
  2. 如果是的话,这个字节的值是多少?

从接收者的角度来看,

  1. TCP 层和应用程序都需要知道这个 FIN 标志/字节。那么TCP层是不是只看FIN标志,而不对流中的字节进行特殊处理呢?
  2. 申请如何通知?通过 FIN 标志,或者通过流中的这个特殊字节?
  3. 申请什么时候通知?就在 TCP 层接收带有 FIN 标志的段时,或者当该段最终在接收者的 TCP 缓冲区中冒泡时?
  4. 如果应用程序在具有 FIN 标志的段最终在 TCP 缓冲区中冒泡之前没有收到特殊通知,则意味着 TCP 层必须以某种方式标记缓冲区,因为 TCP 标头应该已经被剥离。那么FIN是如何标记的呢?

c networking network-programming tcp network-protocols

2
推荐指数
1
解决办法
556
查看次数

Linux 内核如何发现 PCI 设备?

在驱动程序端,pci_register_driver()在加载驱动程序模块时调用,如果模块是内置的,则在启动时调用。(每当添加设备/驱动程序时,驱动程序/设备列表都会循环以查找匹配项,我得到了那部分。)

但是在哪里/何时发现 pci 设备并在总线上注册?我想这是特定于架构的,并且会涉及 x86 上的 BIOS,例如 - BIOS 例程探测 PCI 设备,然后在加载内核之前将结果放在 RAM 中某个位置的列表中,并且每个列表条目都包含单个 pci 的信息设备包括vendorId/deviceId 等。内核然后拿起列表并将它们插入pci_bus_type.p.klist_devices到某个点。但这纯粹是猜测,谁能给一些提示?

c linux-device-driver linux-kernel pci

0
推荐指数
1
解决办法
861
查看次数

'...' 之前预期的主表达式,C++ 编译错误

SO 上有很多类似标题的帖子,但它们似乎是由各种语法错误触发的,而且我还没有看到一致的模式。

\n
using namespace std;\n\nclass A\n{\npublic:\n    A(int a_) : a(a_) {}\n    int a;\n};\n\nint main()\n{\n    A x{3};\n    A y{0};\n\n    if ((y=x).a)\n        cout << y.a << endl;\n        \n    int i = 1;\n    if (int j = i)\n        cout << j << endl;\n    \n    if ((A z = x).a) // error: expected primary-expression before \xe2\x80\x98z\xe2\x80\x99\n        cout << z.a << endl;\n\n    (int m = 1); // error: expected primary-expression before \xe2\x80\x98int\xe2\x80\x99\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我是否错误地假设A z = x是一个赋值表达式,它应该与 具有相同的值z

\n

c++ syntax compiler-errors

0
推荐指数
1
解决办法
2873
查看次数