我试图更多地了解process 0,例如,它是否具有内存描述符(非NULL task_struct->mm字段),以及它与交换或空闲进程有什么关系。在我看来,在启动 cpu 上创建了一个“进程 0”,然后为每个其他 cpu 创建了一个空闲线程idle_threads_init,但我没有找到第一个(我假设是process 0)的创建位置.
更新
根据tychen 引用的live book,这是我对process 0(x86_64)的最新理解,有人可以确认/反驳以下项目吗?
init_task类型化的task_struct定义是静态的,随着任务的内核堆栈init_task.stack = init_stack,内存描述符init_task.mm=NULL和init_task.active_mm=&init_mm,其中堆栈区init_stack和mm_struct init_mm都静态定义。active_mm非空的事实意味着process 0是一个内核进程。还有,init_task.flags=PF_KTHREAD。init_stack的内核堆栈。这使得current宏有意义(自机器启动以来第一次),这使得fork()可能。在这一点之后,内核实际上运行 inprocess 0的上下文。start_kernel-> arch_call_rest_init-> rest_init,在这个函数内部,process 1&2是分叉的。在kernel_init为 调度的函数中,为每个其他逻辑 CPU 创建process …以下代码来自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) 我对此很陌生,但是通过将 gunicorn 与flask/werkzeug 的代码进行比较,我无法理解在nginx 和flask 之间插入gunicorn 的真正好处。想得到一些专家的意见。
就我目前所了解的而言,归结为将 gunicorn 与 werkzeug 的开发服务器进行比较。简而言之,我不明白为什么 werkzeug 的服务器被称为开发服务器,而 gunicorn 被认为是生产就绪的。我能想到的选择gunicorn而不是werkzeug的论点:
上述理由是否成立?其他原因是什么?
顺便说一句,我已经阅读了SO post 1和SO post 2,但它们似乎还没有完全回答我的问题。
我在这里阅读了几篇文章,但仍然对如何setenv()工作感到困惑:
我的理解是,环境变量作为一堆“foo=bar\0”字符串连续存储在用户堆栈的底部,然后有一个envp[]指向这些字符串的指针数组,也靠近堆栈的底部用户堆栈。用户堆栈在这些字节之上增长,这意味着向字符串区域或指针数组添加更多内容并不简单。setenv()那么,如果设置了新变量(需要添加一个元素envp[]),或者更改了变量但新值字符串比旧值字符串长(使得就地修改不可能),而不需要(几乎)移动变量,那么如何工作?整个用户堆栈为新人腾出空间?
一个有点相关的问题是,是否bash保留本地设置变量的内部列表,并且当用户使用export本地设置变量时,bash只需将其从本地管理列表中删除,并将其添加到上述堆栈字符串区域的底部并将其指针插入到指针数组envp[],以便其子进程自动继承导出的变量?
为标题道歉,如果我知道如何更好地表达它,那么谷歌可能已经帮助了我......
我想要一个对象 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 中。
这可能是一个愚蠢的问题,因为我对这个主题不太了解...似乎用户应用程序可以直接与 GPU 对话来渲染图像,例如使用 OpenGL,通过 mesa 和 libdrm,其中 libdrm 是各种 ioctl() 调用的包装器,如下图所示。这是否意味着对于 3D 游戏的每个新帧,游戏应用程序都需要调用 ioctl() 一次(如果需要达到 KMS,甚至可能调用两次)?这听起来像是大量的用户-内核空间障碍跨越(想想 120 fps 的游戏)。
我对系统调用(高级)工作流程的理解是:
如果是这样,那么内核源代码中应该有一堆 sys_xxx() 函数。例如,对于read(),在内核 2.6 代码中,我找到了sys_read。然而,在内核 5.4 代码中,我没有找到这样的服务例程代码,我发现的唯一sys_read就像是 libc 包装器的替代品。所以我很困惑..
一个相关的问题 - 内核将实现放在 sys_xxx() 中的原因是内核空间也可以调用这些函数,对吗?
我的问题实际上分为两部分:
从发送者的角度来看,
从接收者的角度来看,
在驱动程序端,pci_register_driver()在加载驱动程序模块时调用,如果模块是内置的,则在启动时调用。(每当添加设备/驱动程序时,驱动程序/设备列表都会循环以查找匹配项,我得到了那部分。)
但是在哪里/何时发现 pci 设备并在总线上注册?我想这是特定于架构的,并且会涉及 x86 上的 BIOS,例如 - BIOS 例程探测 PCI 设备,然后在加载内核之前将结果放在 RAM 中某个位置的列表中,并且每个列表条目都包含单个 pci 的信息设备包括vendorId/deviceId 等。内核然后拿起列表并将它们插入pci_bus_type.p.klist_devices到某个点。但这纯粹是猜测,谁能给一些提示?
SO 上有很多类似标题的帖子,但它们似乎是由各种语法错误触发的,而且我还没有看到一致的模式。
\nusing 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}\nRun Code Online (Sandbox Code Playgroud)\n我是否错误地假设A z = x是一个赋值表达式,它应该与 具有相同的值z?