2015-11-29 2 views
1

Я пытаюсь отправить сообщение между двумя процессами на Маха (Чтобы быть точным, это Debian GNU/Hurd с микроядра Mach) и это код у меня есть:не удается отправить сообщения между двумя процессами 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 

ВГ ich сообщает мне, что сообщение было успешно поставлено в очередь, но останавливается и не переходит к чтению из очереди в родительском процессе. Любая идея?

ответ

1

Этот код не работает из-за того, что Hurd обрабатывает порты Mach во время fork(). Порт Mach может иметь только одно право на получение, поэтому порты с правами на получение дублируются во время fork(), а права отправки копируются (например, дескрипторы файлов). В этом случае у вас есть право на получение в destination, когда вы fork(), поэтому ребенок получает совершенно новый порт. Каждый процесс имеет право на получение своего собственного порта, и между двумя портами нет связи.

Самый простой способ я нашел, чтобы делать то, что вы хотите 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(), но так мало приложений обменивают raw-порты Mach, что я не думаю, что это имеет смысл. В любом случае fork() на Hurd не является тривиальным процессом: вы можете найти детали here. Строки 207-449 - это то, где права порта копируются в ребенка; просто краткий взгляд должен дать вам представление о том, насколько сложна хардская вилка(), а также почему ваша оригинальная идея не сработала.

Смежные вопросы