2015-11-29 82 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()是多麼複雜,以及爲什麼你的原創想法不起作用。