Code:
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <pthread.h>
typedef struct smem
{
size_t have, want;
void *data;
} smem_t;
typedef struct smemv
{
size_t have;
smem_t *data;
} smemv_t;
#define PIPE_RD 0
#define PIPE_WR 1
#define PIPE_COUNT 2
#ifdef _WIN32
typedef HANDLE pipe_t;
#define INVALID_PIPE NULL
#else
typedef int pipe_t;
#define INVALID_PIPE -1
#endif
int open_pipes( pipe_t *pipes );
void shut_pipes( pipe_t *pipes );
int pipe_err( pipe_t pipe );
ssize_t rdpipe( pipe_t pipe, void *data, size_t size );
ssize_t wrpipe( pipe_t pipe, void *data, size_t size );
#define INVALID_TID -1
typedef struct worker
{
int num;
pthread_t tid;
pipe_t pipes[PIPE_COUNT];
bool attr_created;
pthread_attr_t attr;
} worker_t;
typedef void * (*Worker_t)( void *arg );
void * rdworker( worker_t *worker );
void * wrworker( worker_t *worker );
int main()
{
int i;
pipe_t pipes[PIPE_COUNT] = {INVALID_PIPE,INVALID_PIPE};
worker_t workers[2] = {{0}}, *worker, *worker_ret[2];
if ( open_pipes( pipes ) != 0 )
goto cleanup;
for ( i = 0; i < 2; ++i )
{
worker = &(workers[i]);
worker->num = i + 1;
worker->tid = INVALID_TID;
worker->pipes[PIPE_RD] = pipes[PIPE_RD];
worker->pipes[PIPE_WR] = pipes[PIPE_WR];
worker->attr_created = false;
if ( pthread_attr_init( &(worker->attr) ) != 0 )
goto cleanup;
worker->attr_created = true;
}
worker = &(workers[0]);
if ( pthread_create
(
&(worker->tid)
, &(worker->attr)
, (Worker_t)rdworker
, worker
) != 0
) goto cleanup;
worker = &(workers[1]);
pthread_attr_setdetachstate( &(worker->attr), PTHREAD_CREATE_DETACHED );
if ( pthread_create
(
&(worker->tid)
, &(worker->attr)
, (Worker_t)wrworker
, worker
) != 0
) goto cleanup;
pthread_join( workers[0].tid, (void**)&(worker_ret[0]) );
cleanup:
while ( i > 0 )
{
--i;
worker = &(workers[i]);
if ( worker->num >= 0 )
pthread_cancel( worker->tid );
if ( worker->attr_created )
pthread_attr_destroy( &(worker->attr) );
worker->attr_created = false;
worker->pipes[PIPE_WR] = INVALID_PIPE;
worker->pipes[PIPE_RD] = INVALID_PIPE;
worker->tid = INVALID_TID;
}
shut_pipes( pipes );
printf("Hello World!\n");
return 0;
}
int open_pipes( pipe_t *pipes )
{
pipes[0] = pipes[1] = INVALID_PIPE;
#ifdef _WIN32
#error "Unchecked calls"
pipes[0] = CreatePipe( FILE_READ, 0 );
pipes[1] = CreatePipe( FILE_WRITE, 0 );
return 0;
#else
return pipe( pipes );
#endif
}
void shut_pipes( pipe_t *pipes )
{
#ifdef _WIN32
CloseHandle( pipes[1] );
CloseHandle( pipes[0] );
#else
close( pipes[1] );
close( pipes[0] );
#endif
pipes[0] = pipes[1] = INVALID_PIPE;
}
int pipe_err( pipe_t pipe )
{
return error( pipe );
}
ssize_t rdpipe( pipe_t pipe, void *data, size_t size )
{
#ifdef _WIN32
DWORD bytes = 0;
ReadFile( pipe, data, size, &bytes );
return bytes;
#else
return read( pipe, data, size );
#endif
}
ssize_t wrpipe( pipe_t pipe, void *data, size_t size )
{
#ifdef _WIN32
DWORD bytes = 0;
WriteFile( pipe, data, size, &bytes );
return bytes;
#else
return write( pipe, data, size );
#endif
}
void * rdworker( worker_t *worker )
{
int num = 0;
ssize_t bytes;
struct pollfd fds = {0};
fds.fd = worker->pipes[PIPE_RD];
fds.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
printf( "Worker %d: num = %d\n", worker->num, num );
poll( &fds, 1, 1 );
bytes = rdpipe( worker->pipes[PIPE_RD], &num, sizeof(int) );
printf( "Worker %d: num = %d, Read %zd bytes\n", worker->num, num, bytes );
/* Indicate the thread exited */
worker->num = -1;
return worker;
}
void * wrworker( worker_t *worker )
{
int num = 0x12345678;
size_t bytes;
printf( "Worker %d: num = %d\n", worker->num, num );
bytes = wrpipe( worker->pipes[PIPE_WR], &num, sizeof(int) );
printf( "Worker %d: num = %d, Wrote %zd bytes\n", worker->num, num, bytes );
/* Indicate the thread exited */
worker->num = -1;
return worker;
}