- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将 mach 端口传递给使用 fork
创建的子进程在 Mac OSX 上。我看到了这个问题 Sharing Mach ports with child processes但它没有解决方案,它只是描述了问题。看这个网站https://robert.sesek.com/2014/1/changes_to_xnu_mach_ipc.html它包含将 mach 端口传递给子进程的说明,但不幸的是,它们不是示例代码。
我尝试实现端口交换,但子进程无法接收父进程发送的消息,mach_msg
内部 recv_port
失败 invalid name
.以下是我到目前为止所拥有的。抱歉有这么多代码,mach IPC 有点让人难以简短。
那么,既然 bootstrap 端口 hack 不再有效,我该如何将 mach 端口传递给 Mac OSX 上的子进程?
编辑
我更改了代码示例以反射(reflect) Ken Thomases 在他的回答中提出的观点,子进程创建一个具有发送权限的端口并将其发送给父进程。但是父进程无法接收子进程创建和发送的端口,只是卡在 recv_port
上。 .
#include <stdio.h>
#include <mach/mach.h>
#include <mach/error.h>
#include <mach/message.h>
#include <unistd.h>
static int32_t
send_port(mach_port_t remote_port, mach_port_t port)
{
kern_return_t err;
struct
{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t task_port;
} msg;
msg.header.msgh_remote_port = remote_port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) |
MACH_MSGH_BITS_COMPLEX;
msg.header.msgh_size = sizeof msg;
msg.body.msgh_descriptor_count = 1;
msg.task_port.name = port;
msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
err = mach_msg_send(&msg.header);
if(err != KERN_SUCCESS)
{
mach_error("Can't send mach msg\n", err);
return (-1);
}
return (0);
}
static int32_t
recv_port(mach_port_t recv_port, mach_port_t *port)
{
kern_return_t err;
struct
{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t task_port;
mach_msg_trailer_t trailer;
} msg;
err = mach_msg(&msg.header, MACH_RCV_MSG,
0, sizeof msg, recv_port,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(err != KERN_SUCCESS)
{
mach_error("Can't recieve mach message\n", err);
return (-1);
}
*port = msg.task_port.name;
return 0;
}
static int32_t
setup_recv_port(mach_port_t *recv_port)
{
kern_return_t err;
mach_port_t port = MACH_PORT_NULL;
err = mach_port_allocate(mach_task_self (),
MACH_PORT_RIGHT_RECEIVE, &port);
if(err != KERN_SUCCESS)
{
mach_error("Can't allocate mach port\n", err);
return (-1);
}
err = mach_port_insert_right(mach_task_self (),
port,
port,
MACH_MSG_TYPE_MAKE_SEND);
if(err != KERN_SUCCESS)
{
mach_error("Can't insert port right\n", err);
return (-1);
}
(*recv_port) = port;
return (0);
}
pid_t
fork_pass_port(mach_port_t pass_port, int32_t (*child_start)(mach_port_t port, void *arg), void *arg)
{
pid_t pid = 0;
int32_t rtrn = 0;
kern_return_t err;
mach_port_t special_port = MACH_PORT_NULL;
/* Setup the mach port. */
if(setup_recv_port(&pass_port) != 0)
{
printf("Can't setup mach port\n");
return (-1);
}
/* Grab our current task's(process's) HOST_NAME special port. */
err = task_get_special_port(mach_task_self(), TASK_HOST_PORT, &special_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't get special port:\n", err);
return (-1);
}
/* Set the HOST_NAME special port as the parent recv port. */
err = task_set_special_port(mach_task_self(), TASK_HOST_PORT, pass_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't set special port:\n", err);
return (-1);
}
pid = fork();
if(pid == 0)
{
mach_port_t host_port = MACH_PORT_NULL;
mach_port_t port = MACH_PORT_NULL;
/* In the child process grab the port passed by the parent. */
err = task_get_special_port(mach_task_self(), TASK_HOST_PORT, &pass_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't get special port:\n", err);
return (-1);
}
/* Create a port with a send right. */
if(setup_recv_port(&port) != 0)
{
printf("Can't setup mach port\n");
return (-1);
}
/* Send port to parent. */
rtrn = send_port(pass_port, port);
if(rtrn < 0)
{
printf("Can't send port\n");
return (-1);
}
/* Now that were done passing the mach port, start the function passed by the caller. */
child_start(pass_port, arg);
/* Exit and clean up the child process. */
_exit(0);
}
else if(pid > 0)
{
mach_port_t child_port = MACH_PORT_NULL;
rtrn = recv_port(pass_port, &child_port);
if(rtrn < 0)
{
printf("Can't recv port\n");
return (-1);
}
/* Reset parents special port. */
err = task_set_special_port(mach_task_self(), TASK_HOST_PORT, special_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't set special port:\n", err);
return (-1);
}
return (0);
}
else
{
/* Error, so cleanup the mach port. */
err = mach_port_deallocate(mach_task_self(), pass_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't deallocate mach port\n", err);
return (-1);
}
perror("fork");
return (-1);
}
}
static int32_t start(mach_port_t port, void *arg)
{
printf("Started\n");
return (0);
}
int main(void)
{
char *arg = "argument";
mach_port_t port = MACH_PORT_NULL;
pid_t pid = fork_pass_port(port, start, arg);
if(pid < 0)
{
printf("Can't fork and pass msg port\n");
return (-1);
}
return (0);
}
最佳答案
我想出了如何通过特殊端口继承传递 mach 端口。您必须暂时更换TASK_BOOTSTRAP_PORT
在调用 fork 之前使用您要传递的端口。其他特殊端口以一种或另一种方式失败。下面是一个“端口交换舞蹈”的例子。
请注意,此代码仅在 OSX 10.11.3 上测试过,可能不适用于以前或 future 版本的 OSX。
#include <stdio.h>
#include <mach/mach.h>
#include <mach/error.h>
#include <mach/message.h>
#include <unistd.h>
#define SPECIAL_PORT TASK_BOOTSTRAP_PORT
static int32_t
send_port(mach_port_t remote_port, mach_port_t port)
{
kern_return_t err;
struct
{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t task_port;
} msg;
msg.header.msgh_remote_port = remote_port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) |
MACH_MSGH_BITS_COMPLEX;
msg.header.msgh_size = sizeof msg;
msg.body.msgh_descriptor_count = 1;
msg.task_port.name = port;
msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
err = mach_msg_send(&msg.header);
if(err != KERN_SUCCESS)
{
mach_error("Can't send mach msg\n", err);
return (-1);
}
return (0);
}
static int32_t
recv_port(mach_port_t recv_port, mach_port_t *port)
{
kern_return_t err;
struct
{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t task_port;
mach_msg_trailer_t trailer;
} msg;
err = mach_msg(&msg.header, MACH_RCV_MSG,
0, sizeof msg, recv_port,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if(err != KERN_SUCCESS)
{
mach_error("Can't recieve mach message\n", err);
return (-1);
}
(*port) = msg.task_port.name;
return 0;
}
static int32_t
setup_recv_port(mach_port_t *recv_port)
{
kern_return_t err;
mach_port_t port = MACH_PORT_NULL;
err = mach_port_allocate(mach_task_self (),
MACH_PORT_RIGHT_RECEIVE, &port);
if(err != KERN_SUCCESS)
{
mach_error("Can't allocate mach port\n", err);
return (-1);
}
err = mach_port_insert_right(mach_task_self (),
port,
port,
MACH_MSG_TYPE_MAKE_SEND);
if(err != KERN_SUCCESS)
{
mach_error("Can't insert port right\n", err);
return (-1);
}
(*recv_port) = port;
return (0);
}
static int32_t
start(mach_port_t port, void *arg)
{
return (0);
}
static pid_t
fork_pass_port(mach_port_t *pass_port,
int32_t (*child_start)(mach_port_t port, void *arg),
void *arg)
{
pid_t pid = 0;
int32_t rtrn = 0;
kern_return_t err;
mach_port_t special_port = MACH_PORT_NULL;
/* Allocate the mach port. */
if(setup_recv_port(pass_port) != 0)
{
printf("Can't setup mach port\n");
return (-1);
}
/* Grab our current process's bootstrap port. */
err = task_get_special_port(mach_task_self(), SPECIAL_PORT, &special_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't get special port:\n", err);
return (-1);
}
/* Set the special port as the parent recv port. */
err = task_set_special_port(mach_task_self(), SPECIAL_PORT, (*pass_port));
if(err != KERN_SUCCESS)
{
mach_error("Can't set special port:\n", err);
return (-1);
}
pid = fork();
if(pid == 0)
{
mach_port_t bootstrap_port = MACH_PORT_NULL;
mach_port_t port = MACH_PORT_NULL;
/* In the child process grab the port passed by the parent. */
err = task_get_special_port(mach_task_self(), SPECIAL_PORT, pass_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't get special port:\n", err);
return (-1);
}
/* Create a port with a send right. */
if(setup_recv_port(&port) != 0)
{
printf("Can't setup mach port\n");
return (-1);
}
/* Send port to parent. */
rtrn = send_port((*pass_port), port);
if(rtrn < 0)
{
printf("Can't send port\n");
return (-1);
}
/* Receive the real bootstrap port from the parent. */
rtrn = recv_port(port, &bootstrap_port);
if(rtrn < 0)
{
printf("Can't receive bootstrap port\n");
return (-1);
}
/* Set the bootstrap port back to normal. */
err = task_set_special_port(mach_task_self(), SPECIAL_PORT, bootstrap_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't set special port:\n", err);
return (-1);
}
/* Now that were done with the port dance, start the function passed by the caller. */
child_start((*pass_port), arg);
/* Exit and clean up the child process. */
_exit(0);
}
else if(pid > 0)
{
mach_port_t child_port = MACH_PORT_NULL;
/* Grab the child's recv port. */
rtrn = recv_port((*pass_port), &child_port);
if(rtrn < 0)
{
printf("Can't recv port\n");
return (-1);
}
/* Send the child the original bootstrap port. */
rtrn = send_port(child_port, special_port);
if(rtrn < 0)
{
printf("Can't send bootstrap port\n");
return (-1);
}
/* Reset parents special port. */
err = task_set_special_port(mach_task_self(), SPECIAL_PORT, special_port);
if(err != KERN_SUCCESS)
{
mach_error("Can't set special port:\n", err);
return (-1);
}
return (0);
}
else
{
/* Error, so cleanup the mach port. */
err = mach_port_deallocate(mach_task_self(), (*pass_port));
if(err != KERN_SUCCESS)
{
mach_error("Can't deallocate mach port\n", err);
return (-1);
}
perror("fork");
return (-1);
}
}
int main(void)
{
/* Argument to pass to the child process. */
char *arg = "argument";
/* Mach port we want to pass to the child. */
mach_port_t port = MACH_PORT_NULL;
pid_t pid = fork_pass_port(&port, start, arg);
if(pid < 0)
{
printf("Can't fork and pass msg port\n");
return (-1);
}
return (0);
}
关于c - 将 mach 端口传递给子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34866604/
Github:https://github.com/jjvang/PassIntentDemo 我一直在关注有关按 Intent 传递对象的教程:https://www.javacodegeeks.c
我有一个 View ,其中包含自动生成的 text 类型的 input 框。当我单击“通过电子邮件发送结果”按钮时,代码会将您带到 CalculatedResults Controller 中的 Em
我有一个基本的docker镜像,我将以此为基础构建自己的镜像。我没有基础镜像的Dockerfile。 基本上,基本镜像使用两个--env arg,一个接受其许可证,一个选择在容器中激活哪个框架。我可以
假设我想计算 2^n 的总和,n 范围从 0 到 100。我可以编写以下内容: seq { 0 .. 100 } |> Seq.sumBy ((**) 2I) 但是,这与 (*) 或其他运算符/函数不
我有这个网址: http://www.example.com/get_url.php?ID=100&Link=http://www.test.com/page.php?l=1&m=7 当我打印 $_G
我想将 window.URL.createObjectURL(file) 创建的地址传递给 dancer.js 但我得到 GET blob:http%3A//localhost/b847c5cd-aa
我想知道如何将 typedef 传递给函数。例如: typedef int box[3][3]; box empty, *board[3][3]; 我如何将 board 传递给函数?我
我正在将一些代码从我的 Controller 移动到核心数据应用程序中的模型。 我编写了一个方法,该方法为我定期发出的特定获取请求返回 NSManagedObjectID。 + (NSManagedO
为什么我不能将类型化数组传递到采用 any[] 的函数/构造函数中? typedArray = new MyType[ ... ]; items = new ko.observableArray(ty
我是一名新的 Web 开发人员,正在学习 html5 和 javascript。 我有一个带有“选项卡”的网页,可以使网页的某些部分消失并重新出现。 链接如下: HOME 和 JavaScript 函
我试图将对函数的引用作为参数传递 很难解释 我会写一些伪代码示例 (calling function) function(hello()); function(pass) { if this =
我在尝试调用我正在创建的 C# 项目中的函数时遇到以下错误: System.Runtime.InteropServices.COMException: Operation is not allowed
使用 ksh。尝试重用当前脚本而不修改它,基本上可以归结为如下内容: `expr 5 $1 $2` 如何将乘法命令 (*) 作为参数 $1 传递? 我首先尝试使用“*”,甚至是\*,但没有用。我尝试
我一直在研究“Play for Java”这本书,这本书非常棒。我对 Java 还是很陌生,但我一直在关注这些示例,我有点卡在第 3 章上了。可以在此处找到代码:Play for Java on Gi
我知道 Javascript 中的对象是通过引用复制/传递的。但是函数呢? 当我跳到一些令人困惑的地方时,我正在尝试这段代码。这是代码片段: x = function() { console.log(
我希望能够像这样传递参数: fn(a>=b) or fn(a!=b) 我在 DjangoORM 和 SQLAlchemy 中看到了这种行为,但我不知道如何实现它。 最佳答案 ORM 使用 specia
在我的 Angular 项目中,我最近将 rxjs 升级到版本 6。现在,来自 npm 的模块(在 node_modules 文件夹内)由于一些破坏性更改而失败(旧的进口不再有效)。我为我的代码调整了
这个问题在这里已经有了答案: The issue of * in Command line argument (6 个答案) 关闭 3 年前。 我正在编写一个关于反向波兰表示法的 C 程序,它通过命
$(document).ready(function() { function GetDeals() { alert($(this).attr("id")); } $('.filter
下面是一个例子: 复制代码 代码如下: use strict; #这里是两个数组 my @i =('1','2','3'); my @j =('a','b','c'); &n
我是一名优秀的程序员,十分优秀!