2015-11-29 33 views
1

我想马赫两个进程之间发送消息(准确地说,这是的Debian GNU/Hurd的一个Mach微),这是我的代码:不能在两个进程之间发送消息马赫

#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 

WH ich告诉我消息已成功排队,但在那里停止,并且不从父进程的队列读取数据。 有什么想法?

回答

1

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

我发现你想要做什么,最简单的方法是Kalle Niemitalo's suggestion: 使用赫德的proc服务器,其中包含发送权限系统中的每个进程的任务端口,会给他们拿出来与匹配任何进程UID。一个任务端口可以让你几乎做任何你想要的过程:修改它的内存,启动和停止它的线程......并改变它的端口空间。

因此,在这种情况下,您希望孩子向父母发送消息。孩子可以使用父母的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。

另一种方法是在fork()上修改Hurd的行为,但很少应用程序交换原始Mach端口,我认为这不合理。无论如何,Hurd上的fork()并不是一个简单的过程:你可以找到细节here。第207-449行是将港口权利复制到儿童的地方;只需简短的一瞥即可了解赫德的fork()是多么复杂,以及为什么你的原创想法不起作用。