无法在两个进程 Mach 之间发送消息

标签 c debian gnu mach

我正在尝试在 Mach 上的两个进程之间发送消息(准确地说,这是带有 Mach 微内核的 D​​ebian GNU/Hurd),这是我的代码:

#define _GNU_SOURCE

#include "machheader.h"

void 
send_integer( mach_port_t destination, int i )
{
    kern_return_t err;
    struct integer_message message;

    /* (i) Form the message : */

    /* (i.a) Fill the header fields : */
    message.head.msgh_bits = 
        MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND);
    message.head.msgh_size = sizeof( struct integer_message );
    message.head.msgh_local_port = MACH_PORT_NULL;
    message.head.msgh_remote_port = destination;

    /* (i.b) Explain the message type ( an integer ) */
    message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
    message.type.msgt_size = 32;
    message.type.msgt_number = 1;
    message.type.msgt_inline = TRUE;
    message.type.msgt_longform = FALSE;
    message.type.msgt_deallocate = FALSE;
    /* message.type.msgt_unused = 0; */ /* not needed, I think */

    /* (i.c) Fill the message with the given integer : */
    message.inline_integer = i;

    /* (ii) Send the message : */
    err = mach_msg( &(message.head), MACH_SEND_MSG, 
            message.head.msgh_size, 0, MACH_PORT_NULL, 
            MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL );

    /* (iii) Analysis of the error code; 
    if succes, print and acknowledge message and return */
    if( err == MACH_MSG_SUCCESS )
      {
        printf( "success: the message was queued\n" );
      }
    else
      {
        perror( "error: some unexpected error ocurred!\n");
        exit(err);
      }

    return;
}

/* receive_integer is a function that receives an integer from some 
   mach port; it also hides the complexity of using the mach_msg 
   primitive to the user.

   receive_integer takes two arguments; the port where the message is going
   to come from with an integer inside, and a pointer to an integer in where
   the integer contained in the mentioned message will be stored.
*/
void 
receive_integer( mach_port_t source, int *ip )
{
    kern_return_t err;

    struct integer_message message;

    /* (i) Fill the little thing we know about the message : */
    /* message.head.msgh_size = sizeof(struct integer_message ); */

    /* (ii) Receive the message : */
    err = mach_msg( &(message.head), MACH_RCV_MSG, 0, 
            message.head.msgh_size, source,
            MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL );

    if( err == MACH_MSG_SUCCESS )
      {
        printf( "success: the message was received\n" );
      }
    else
      {
        perror( "error: Some unexpected error ocurred\n" );
        exit(err);
      }

    *ip = message.inline_integer;

    return;
}

/* main function of the program; it does the following :

   (i) allocate a port for receiving a message
   (ii) send a message containing an integer; 
   it uses the send_integer function
   (iii) receive the message and display it;
   it uses the receive_integer function
   (iv) deallocate the port
*/
int 
main( void )
{       
    //int s, r; /* s -> int sent, r -> int received */ 
    //mach_port_t destination;    

    kern_return_t err;

    /* Allocate a port to receive the bootstrap message : */
    err = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
        &destination );

    if( err != KERN_SUCCESS )
      {
        perror( "Error : could not allocate any port\n" );
        exit(err);
      }

    if(!fork()){
        s=7;
        send_integer( destination, s );
    }else{
        receive_integer( destination, &r );
        printf("The received integer is : %d\n", r );
    }   

    mach_port_deallocate( mach_task_self(), destination );

    return(r);
} 

这是 machheader.h:

#include <mach.h>

#include <stdio.h>
#include <error.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>

struct integer_message
{
    mach_msg_header_t head;
    mach_msg_type_t type;

    int inline_integer;
};

int s, r;   /* s -> int sent, r -> int received */ 
mach_port_t destination;

当我运行应用程序时,它会给我:

success: the message was queued

这告诉我消息已成功排队但停在那里并且不会继续从父进程的队列中读取。 有什么想法吗?

最佳答案

由于 Hurd 在 fork() 期间处理 Mach 端口的方式,此代码不起作用。一个 Mach 端口只能有一个接收权,因此具有接收权的端口在 fork() 期间被复制,而发送权被复制(如文件描述符)。在这种情况下,当您 fork() 时,您在 destination 中获得了接收权,因此子进程获得了一个全新的端口。然后每个进程都有对其自己端口的接收权,并且两个端口之间没有连接。

我发现做你想做的最简单的方法是 Kalle Niemitalo's suggestion : 使用 Hurd 的 proc 服务器,它拥有系统中每个进程的任务端口的发送权限,并将它们发送给任何具有匹配 UID 的进程。任务端口让您几乎可以对进程执行任何您想做的事情:修改其内存、启动和停止其线程……以及更改其端口空间。

因此,在这种情况下,您希望 child 向 parent 发送消息。子进程可以使用父进程的 PID 获取到父进程的任务端口,然后提取到父进程的 destination 端口的发送权,然后向该端口发送消息。像这样:

if(!fork()){
    /* fork allocated a receive right in the child process, but it's not
       for the same port as in the parent process.  Deallocate that.  */
    mach_port_mod_refs (mach_task_self(), destination,
                        MACH_PORT_RIGHT_RECEIVE, -1);

    /* get a send right to the parent's task port */
    pid_t parent_pid = getppid ();
    task_t parent_task = pid2task (parent_pid);

    /* extract a send right to the parent's destination port */
    mach_port_t send_right;
    mach_port_type_t send_type;

    mach_port_extract_right (parent_task, destination,
                             MACH_MSG_TYPE_MAKE_SEND,
                             &send_right, &send_type);

    /* transmit to "send_right", not "destination" */
    s=7;
    send_integer( send_right, s );
}else{
    receive_integer( destination, &r );
    printf("The received integer is : %d\n", r );
}

子进程可以像这样在父进程上运行似乎有点奇怪;但这是赫德的一个特点。 proc 是一个高权限服务器;它允许访问,因为这两个进程具有相同的 UID。

另一种方法是修改 Hurd 在 fork() 上的行为,但很少有应用程序交换原始 Mach 端口,我认为这没有意义。无论如何,赫德的 fork() 不是一个简单的过程:您可以找到详细信息 here .第 207-449 行是将端口权复制到子进程的地方;只需快速浏览一下,您就可以了解 Hurd 的 fork() 有多么复杂,以及您最初的想法为何行不通。

关于无法在两个进程 Mach 之间发送消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33979316/

相关文章:

c - 从结构中释放内存给出无效指针

C 代码(带逗号运算符)到 Delphi

linux - 外部解析dns linux bin9

linux - 在终端上进行大规模重命名并按顺序编号

windows - GNU sed - 查找或替换空格或新行。为什么这不起作用? v3.02 与 v4.2

c - 在计算字符数后输入文本和 malloc 可能吗? ( C )

C编程。文件 I/O、链接列表和结构

Linux Debian 9 守护进程标准输入 (bash)

linux - 附加了 '~' 的 Debian 重复文件

python - 尝试安装 Python 包时出现 "iconv.h: No such file"