git-svn-id: svn+ssh://jackaudio.org/trunk/jack@768 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -15,7 +15,7 @@ dnl changes are made | |||
| dnl --- | |||
| JACK_MAJOR_VERSION=0 | |||
| JACK_MINOR_VERSION=99 | |||
| JACK_MICRO_VERSION=4 | |||
| JACK_MICRO_VERSION=5 | |||
| dnl --- | |||
| dnl HOWTO: updating the jack protocol version | |||
| @@ -25,7 +25,7 @@ dnl made to the way libjack communicates with jackd | |||
| dnl that would break applications linked with an older | |||
| dnl version of libjack. | |||
| dnl --- | |||
| JACK_PROTOCOL_VERSION=13 | |||
| JACK_PROTOCOL_VERSION=14 | |||
| dnl --- | |||
| dnl HOWTO: updating the libjack interface version | |||
| @@ -16,30 +16,52 @@ jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_client_t *client; | |||
| /* a simple state machine for this client */ | |||
| volatile enum { | |||
| Init, | |||
| Run, | |||
| Exit | |||
| } client_state = Init; | |||
| /** | |||
| * The process callback for this JACK application. | |||
| * It is called by JACK at the appropriate times. | |||
| * The process callback for this JACK application is called in a | |||
| * special realtime thread once for each audio cycle. | |||
| * | |||
| * This client follows a simple rule: when the JACK transport is | |||
| * running, copy the input port to the output. When it stops, exit. | |||
| */ | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); | |||
| jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); | |||
| jack_default_audio_sample_t *in, *out; | |||
| jack_transport_state_t ts = jack_transport_query(client, NULL); | |||
| if (ts == JackTransportRolling) { | |||
| if (client_state == Init) | |||
| client_state = Run; | |||
| memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); | |||
| in = jack_port_get_buffer (input_port, nframes); | |||
| out = jack_port_get_buffer (output_port, nframes); | |||
| memcpy (out, in, | |||
| sizeof (jack_default_audio_sample_t) * nframes); | |||
| } else if (ts == JackTransportStopped) { | |||
| if (client_state == Run) | |||
| client_state = Exit; | |||
| } | |||
| return 0; | |||
| } | |||
| /** | |||
| * This is the shutdown callback for this JACK application. | |||
| * It is called by JACK if the server ever shuts down or | |||
| * JACK calls this shutdown_callback if the server ever shuts down or | |||
| * decides to disconnect the client. | |||
| */ | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| @@ -47,17 +69,34 @@ int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char **ports; | |||
| if (argc < 2) { | |||
| fprintf (stderr, "usage: jack_simple_client <name>\n"); | |||
| return 1; | |||
| const char *client_name; | |||
| jack_status_t status; | |||
| if (argc >= 2) { /* session name specified? */ | |||
| client_name = argv[1]; | |||
| } else { /* use basename of argv[0] */ | |||
| client_name = strrchr(argv[0], '/'); | |||
| if (client_name == 0) { | |||
| client_name = argv[0]; | |||
| } else { | |||
| client_name++; | |||
| } | |||
| } | |||
| /* try to become a client of the JACK server */ | |||
| /* open a client connection to the JACK server */ | |||
| if ((client = jack_client_new (argv[1])) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| client = jack_client_open (client_name, 0, &status, NULL, NULL); | |||
| if (client == NULL) { | |||
| fprintf (stderr, "jack_client_open() failed, status = %d\n", | |||
| status); | |||
| exit (1); | |||
| } | |||
| if (status & JackServerStarted) { | |||
| fprintf (stderr, "JACK server started\n"); | |||
| } | |||
| if (status & JackNameNotUnique) { | |||
| client_name = jack_get_client_name(client); | |||
| fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| @@ -81,25 +120,31 @@ main (int argc, char *argv[]) | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
| input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| /* tell the JACK server that we are ready to roll */ | |||
| /* Tell the JACK server that we are ready to roll. Our | |||
| * process() callback will start running now. */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| return 1; | |||
| exit (1); | |||
| } | |||
| /* connect the ports. Note: you can't do this before | |||
| the client is activated, because we can't allow | |||
| connections to be made to clients that aren't | |||
| running. | |||
| /* connect the ports. Note: you can't do this before the | |||
| client is activated, because we can't allow connections to | |||
| be made to clients that aren't running. | |||
| */ | |||
| if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) { | |||
| fprintf(stderr, "Cannot find any physical capture ports\n"); | |||
| exit(1); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsOutput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical capture ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| @@ -108,9 +153,11 @@ main (int argc, char *argv[]) | |||
| free (ports); | |||
| if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { | |||
| fprintf(stderr, "Cannot find any physical playback ports\n"); | |||
| exit(1); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsInput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical playback ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| @@ -119,10 +166,12 @@ main (int argc, char *argv[]) | |||
| free (ports); | |||
| /* Since this is just a toy, run for a few seconds, then finish */ | |||
| /* keep running until the transport stops */ | |||
| while (client_state != Exit) { | |||
| sleep (1); | |||
| } | |||
| sleep (10); | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -170,7 +170,7 @@ typedef volatile struct { | |||
| volatile jack_client_id_t id; /* w: engine r: engine and client */ | |||
| volatile jack_nframes_t nframes; /* w: engine r: client */ | |||
| volatile jack_client_state_t state; /* w: engine and client r: engine */ | |||
| volatile int8_t name[JACK_CLIENT_NAME_SIZE]; | |||
| volatile char name[JACK_CLIENT_NAME_SIZE]; | |||
| volatile ClientType type; /* w: engine r: engine and client */ | |||
| volatile int8_t active; /* w: engine r: engine and client */ | |||
| volatile int8_t dead; /* r/w: engine */ | |||
| @@ -228,6 +228,7 @@ typedef struct { | |||
| int32_t load; | |||
| ClientType type; | |||
| jack_options_t options; | |||
| char name[JACK_CLIENT_NAME_SIZE]; | |||
| char object_path[PATH_MAX+1]; | |||
| @@ -237,10 +238,10 @@ typedef struct { | |||
| typedef struct { | |||
| int32_t status; | |||
| int32_t status; /* messy name overloading */ | |||
| uint32_t protocol_v; | |||
| jack_status_t open_status; /* used for open() */ | |||
| jack_shm_info_t client_shm; | |||
| jack_shm_info_t engine_shm; | |||
| @@ -249,6 +250,8 @@ typedef struct { | |||
| int32_t realtime; | |||
| int32_t realtime_priority; | |||
| char name[JACK_CLIENT_NAME_SIZE]; /* unique name, if assigned */ | |||
| /* these two are valid only if the connect request | |||
| was for type == ClientDriver. | |||
| */ | |||
| @@ -323,8 +326,8 @@ struct _jack_request { | |||
| int32_t status; | |||
| }; | |||
| /* per-client structure allocated in the server's address space | |||
| * its here because its not part of the engine structure. | |||
| /* Per-client structure allocated in the server's address space. | |||
| * It's here because its not part of the engine structure. | |||
| */ | |||
| typedef struct _jack_client_internal { | |||
| @@ -58,10 +58,10 @@ extern "C" { | |||
| * possible concurrent server instances. If unspecified, "default" is | |||
| * assumed. Server names are unique to each user. | |||
| * | |||
| * @param start_command (if non-NULL) is a command line to use if the | |||
| * server was not running and must be started. Defining | |||
| * $JACK_NO_START_SERVER in the environment disables automatic server | |||
| * creation. | |||
| * @param server_command (if non-NULL) is a command line to start the | |||
| * server if it was not running. The @ref JackNoStartServer option | |||
| * disables automatic server creation, as does defining | |||
| * $JACK_NO_START_SERVER in the environment. | |||
| * | |||
| * @return Opaque client handle if successful. If this is NULL, the | |||
| * open operation failed, and the caller is not a JACK client. | |||
| @@ -70,7 +70,7 @@ jack_client_t *jack_client_open (const char *client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status, | |||
| const char *server_name, | |||
| const char *start_command); | |||
| const char *server_command); | |||
| /** | |||
| * Attempt to become an external client of the Jack server. | |||
| @@ -1001,29 +1001,96 @@ jack_client_unload (jack_client_internal_t *client) | |||
| } | |||
| } | |||
| static jack_client_internal_t * | |||
| jack_client_lookup_name (jack_engine_t *engine, char *name) | |||
| { | |||
| JSList *node; | |||
| jack_lock_graph (engine); | |||
| for (node = engine->clients; node; node = jack_slist_next (node)) { | |||
| jack_client_internal_t *client = node->data; | |||
| if (strncmp(name, (char *) client->control->name, | |||
| JACK_CLIENT_NAME_SIZE) == 0) { | |||
| jack_unlock_graph (engine); | |||
| return client; /* name exists */ | |||
| } | |||
| } | |||
| jack_unlock_graph (engine); | |||
| return NULL; /* not found */ | |||
| } | |||
| /* generate a unique client name | |||
| * | |||
| * returns 0 if successful, updates name in place | |||
| */ | |||
| static inline int | |||
| jack_generate_unique_name (jack_engine_t *engine, char *name) | |||
| { | |||
| int tens, ones; | |||
| int length = strlen (name); | |||
| if (length > JACK_CLIENT_NAME_SIZE - 4) { | |||
| jack_error ("%s exists and is too long to make unique", name); | |||
| return 1; /* failure */ | |||
| } | |||
| /* generate a unique name by appending "-01".."-99" */ | |||
| name[length++] = '-'; | |||
| tens = length++; | |||
| ones = length++; | |||
| name[tens] = '0'; | |||
| name[ones] = '1'; | |||
| name[length] = '\0'; | |||
| while (jack_client_lookup_name (engine, name)) { | |||
| if (name[ones] == '9') { | |||
| if (name[tens] == '9') { | |||
| jack_error ("client %s has 99 extra" | |||
| " instances already", name); | |||
| return 1; /* give up */ | |||
| } | |||
| name[tens]++; | |||
| name[ones] = '0'; | |||
| } else { | |||
| name[ones]++; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| static jack_client_internal_t * | |||
| setup_client (jack_engine_t *engine, int client_fd, | |||
| jack_client_connect_request_t *req, | |||
| jack_client_connect_result_t *res) | |||
| { | |||
| JSList *node; | |||
| jack_client_internal_t *client = NULL; | |||
| jack_client_internal_t *client; | |||
| for (node = engine->clients; node; node = jack_slist_next (node)) { | |||
| client = (jack_client_internal_t *) node->data; | |||
| /* Since this thread already holds the request_lock, no other | |||
| * new client will be created at the same time. So, testing a | |||
| * name for uniqueness is valid here. */ | |||
| //JOQ: watch out for internal clients, they come here too | |||
| if (jack_client_lookup_name (engine, req->name)) { | |||
| if (strncmp(req->name, (char*)client->control->name, | |||
| sizeof(req->name)) == 0) { | |||
| jack_error ("cannot create new client; %s already" | |||
| " exists", client->control->name); | |||
| res->open_status |= JackNameNotUnique; | |||
| if (req->options & JackUseExactName) { | |||
| jack_error ("cannot create new client; %s already" | |||
| " exists", req->name); | |||
| return NULL; | |||
| } | |||
| if (jack_generate_unique_name(engine, req->name)) { | |||
| return NULL; /* failure */ | |||
| } | |||
| } | |||
| if ((client = jack_setup_client_control (engine, client_fd, req)) | |||
| == NULL) { | |||
| /* create a client struct for this client name */ | |||
| client = jack_setup_client_control (engine, client_fd, req); | |||
| if (client == NULL) { | |||
| jack_error ("cannot create new client object"); | |||
| return 0; | |||
| return NULL; | |||
| } | |||
| VERBOSE (engine, "new client: %s, id = %" PRIu32 | |||
| @@ -1036,6 +1103,7 @@ setup_client (jack_engine_t *engine, int client_fd, | |||
| res->engine_shm = engine->control_shm; | |||
| res->realtime = engine->control->real_time; | |||
| res->realtime_priority = engine->rtpriority - 1; | |||
| strncpy (res->name, req->name, sizeof(res->name)); | |||
| #ifdef JACK_USE_MACH_THREADS | |||
| /* specific resources for server/client real-time thread | |||
| @@ -1271,8 +1339,10 @@ handle_new_client (jack_engine_t *engine, int client_fd) | |||
| jack_client_internal_t *client; | |||
| jack_client_connect_request_t req; | |||
| jack_client_connect_result_t res; | |||
| //JOQ: fix messy overloading of `status' | |||
| res.status = 0; | |||
| res.open_status = 0; | |||
| if (read (client_fd, &req, sizeof (req)) != sizeof (req)) { | |||
| jack_error ("cannot read connection request from client"); | |||
| @@ -3,4 +3,5 @@ | |||
| Makefile | |||
| Makefile.in | |||
| *.lo | |||
| *.loT | |||
| *.la | |||
| @@ -1,3 +1,7 @@ | |||
| 2004-10-08 Jack O'Quin <joq@io.com> | |||
| * new API functions: jack_client_open(), jack_get_client_name() | |||
| 2004-09-15 Jack O'Quin <joq@io.com> | |||
| * new API functions from <jack/thread.h> | |||
| @@ -330,10 +330,11 @@ jack_handle_reorder (jack_client_t *client, jack_event_t *event) | |||
| } | |||
| static int | |||
| server_connect (int which) | |||
| server_connect (const char *server_name) | |||
| { | |||
| int fd; | |||
| struct sockaddr_un addr; | |||
| int which = 0; | |||
| if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { | |||
| jack_error ("cannot create client socket (%s)", | |||
| @@ -341,6 +342,7 @@ server_connect (int which) | |||
| return -1; | |||
| } | |||
| //JOQ: use server_name as part of socket path | |||
| addr.sun_family = AF_UNIX; | |||
| snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_%d_%d", | |||
| jack_server_dir, getuid (), which); | |||
| @@ -406,7 +408,7 @@ server_event_connect (jack_client_t *client) | |||
| /* Exec the JACK server in this process. Does not return. */ | |||
| static void | |||
| _start_server (void) | |||
| _start_server (const char *server_command) | |||
| { | |||
| FILE* fp = 0; | |||
| char filename[255]; | |||
| @@ -420,6 +422,10 @@ _start_server (void) | |||
| int good = 0; | |||
| int ret; | |||
| //JOQ: | |||
| // if (start_command) { | |||
| // parse user-supplied command | |||
| // } else { | |||
| snprintf(filename, 255, "%s/.jackdrc", getenv("HOME")); | |||
| fp = fopen(filename, "r"); | |||
| @@ -453,12 +459,12 @@ _start_server (void) | |||
| #endif /* USE_CAPABILITIES */ | |||
| } else { | |||
| result = strcspn(arguments, " "); | |||
| command = (char*)malloc(result+1); | |||
| command = (char *) malloc(result+1); | |||
| strncpy(command, arguments, result); | |||
| command[result] = '\0'; | |||
| } | |||
| argv = (char**)malloc(255); | |||
| argv = (char **) malloc (255); | |||
| while(1) { | |||
| /* insert -T into arguments */ | |||
| @@ -491,12 +497,10 @@ _start_server (void) | |||
| } | |||
| int | |||
| start_server (void) | |||
| start_server (jack_options_t options, const char *server_command) | |||
| { | |||
| /* Only fork() a server when $JACK_START_SERVER is defined and | |||
| * $JACK_NO_START_SERVER is not. */ | |||
| if (getenv("JACK_START_SERVER") == NULL || | |||
| getenv("JACK_NO_START_SERVER") != NULL) { | |||
| if ((options & JackNoStartServer) | |||
| || (getenv("JACK_NO_START_SERVER") != NULL)) { | |||
| return 1; | |||
| } | |||
| @@ -513,7 +517,7 @@ start_server (void) | |||
| case 0: /* child process */ | |||
| switch (fork()) { | |||
| case 0: /* grandchild process */ | |||
| _start_server(); | |||
| _start_server(server_command); | |||
| _exit (99); /* exec failed */ | |||
| case -1: | |||
| _exit (98); | |||
| @@ -531,7 +535,9 @@ start_server (void) | |||
| static int | |||
| jack_request_client (ClientType type, const char* client_name, | |||
| const char* so_name, const char* so_data, | |||
| jack_client_connect_result_t *res, int *req_fd) | |||
| jack_client_connect_result_t *res, int *req_fd, | |||
| jack_options_t options, jack_status_t *status, | |||
| const char *server_name, const char *server_command) | |||
| { | |||
| jack_client_connect_request_t req; | |||
| @@ -539,6 +545,8 @@ jack_request_client (ClientType type, const char* client_name, | |||
| memset (&req, 0, sizeof (req)); | |||
| req.options = options; | |||
| if (strlen (client_name) >= sizeof (req.name)) { | |||
| jack_error ("\"%s\" is too long to be used as a JACK client" | |||
| " name.\n" | |||
| @@ -563,9 +571,9 @@ jack_request_client (ClientType type, const char* client_name, | |||
| return -1; | |||
| } | |||
| if ((*req_fd = server_connect (0)) < 0) { | |||
| if ((*req_fd = server_connect (server_name)) < 0) { | |||
| int trys; | |||
| if (start_server()) { | |||
| if (start_server(options, server_command)) { | |||
| goto fail; | |||
| } | |||
| trys = 5; | |||
| @@ -574,7 +582,8 @@ jack_request_client (ClientType type, const char* client_name, | |||
| if (--trys < 0) { | |||
| goto fail; | |||
| } | |||
| } while ((*req_fd = server_connect (0)) < 0); | |||
| } while ((*req_fd = server_connect (server_name)) < 0); | |||
| *status |= JackServerStarted; | |||
| } | |||
| req.load = TRUE; | |||
| @@ -603,6 +612,9 @@ jack_request_client (ClientType type, const char* client_name, | |||
| goto fail; | |||
| } | |||
| *status |= res->open_status; /* return server status bits */ | |||
| //JOQ: fixme overloading confusion | |||
| if (res->status) { | |||
| jack_error ("could not attach as client " | |||
| "(duplicate client name?)"); | |||
| @@ -707,17 +719,27 @@ jack_attach_port_segment (jack_client_t *client, jack_port_type_id_t ptid) | |||
| } | |||
| jack_client_t * | |||
| jack_client_new (const char *client_name) | |||
| jack_client_open (const char *client_name, | |||
| jack_options_t options, | |||
| jack_status_t *status, | |||
| const char *server_name, | |||
| const char *server_command) | |||
| { | |||
| int req_fd = -1; | |||
| int ev_fd = -1; | |||
| jack_client_connect_result_t res; | |||
| jack_client_t *client; | |||
| jack_port_type_id_t ptid; | |||
| jack_status_t my_status; | |||
| /* external clients need this initialized; internal clients | |||
| will use the setup in the server's address space. | |||
| */ | |||
| if (status == NULL) /* no status from caller? */ | |||
| status = &my_status; /* use local status word */ | |||
| *status = 0; | |||
| /* External clients need this initialized. It is already set | |||
| * up in the server's address space for internal clients. | |||
| */ | |||
| jack_init_time (); | |||
| if (jack_initialize_shm ()) { | |||
| @@ -726,17 +748,19 @@ jack_client_new (const char *client_name) | |||
| } | |||
| if (jack_request_client (ClientExternal, client_name, "", "", | |||
| &res, &req_fd)) { | |||
| &res, &req_fd, options, status, | |||
| server_name, server_command)) { | |||
| return NULL; | |||
| } | |||
| client = jack_client_alloc (); | |||
| strcpy (client->name, res.name); | |||
| strcpy (client->fifo_prefix, res.fifo_prefix); | |||
| client->request_fd = req_fd; | |||
| client->pollfd[EVENT_POLL_INDEX].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| client->pollfd[WAIT_POLL_INDEX].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| client->pollfd[EVENT_POLL_INDEX].events = | |||
| POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| client->pollfd[WAIT_POLL_INDEX].events = | |||
| POLLIN|POLLERR|POLLHUP|POLLNVAL; | |||
| /* attach the engine control/info block */ | |||
| client->engine_shm = res.engine_shm; | |||
| @@ -824,13 +848,31 @@ jack_client_new (const char *client_name) | |||
| return 0; | |||
| } | |||
| jack_client_t * | |||
| jack_client_new (const char *client_name) | |||
| { | |||
| jack_options_t options = JackUseExactName; | |||
| if (getenv("JACK_START_SERVER") == NULL) | |||
| options |= JackNoStartServer; | |||
| return jack_client_open (client_name, options, NULL, NULL, NULL); | |||
| } | |||
| char * | |||
| jack_get_client_name (jack_client_t *client) | |||
| { | |||
| return client->name; | |||
| } | |||
| int | |||
| jack_internal_client_new (const char *client_name, const char *so_name, const char *so_data) | |||
| { | |||
| jack_client_connect_result_t res; | |||
| int req_fd; | |||
| return jack_request_client (ClientInternal, client_name, so_name, so_data, &res, &req_fd); | |||
| return jack_request_client (ClientInternal, client_name, so_name, | |||
| so_data, &res, &req_fd, | |||
| 0, NULL, NULL, NULL); | |||
| } | |||
| void | |||
| @@ -842,7 +884,7 @@ jack_internal_client_close (const char *client_name) | |||
| req.load = FALSE; | |||
| snprintf (req.name, sizeof (req.name), "%s", client_name); | |||
| if ((fd = server_connect (0)) < 0) { | |||
| if ((fd = server_connect (NULL)) < 0) { | |||
| return; | |||
| } | |||
| @@ -31,7 +31,8 @@ struct _jack_client { | |||
| char thread_ok : 1; | |||
| char first_active : 1; | |||
| pthread_t thread_id; | |||
| char name[JACK_CLIENT_NAME_SIZE]; | |||
| #ifdef JACK_USE_MACH_THREADS | |||
| /* specific ressources for server/client real-time thread communication */ | |||
| mach_port_t clienttask, bp, serverport, replyport; | |||