Sample programs

Here are the complete versions of some of the sample programs.

time1.c

For more information about this program, see Server-maintained timeouts.

/*
 *  time1.c
 *
 *  Example of a server that receives periodic messages from
 *  a timer, and regular messages from a client.
 *
 *  Illustrates using the timer functions with a pulse.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/siginfo.h>
#include <sys/neutrino.h>

// message send definitions

// messages
#define MT_WAIT_DATA        2       // message from client
#define MT_SEND_DATA        3       // message from client

// pulses
#define CODE_TIMER          1       // pulse from timer

// message reply definitions
#define MT_OK               0       // message to client
#define MT_TIMEDOUT         1       // message to client

// message structure
typedef struct
{
    int messageType;                // contains both message to and from client
    int messageData;                // optional data, depending upon message
} ClientMessageT;

typedef union
{
    ClientMessageT  msg;            // a message can be either from a client, or
    struct _pulse   pulse;          // a pulse
} MessageT;

// client table
#define MAX_CLIENT 16               // maximum number of simultaneous clients

struct
{
    int in_use;                     // is this client entry in use?
    int rcvid;                      // receive ID of client
    int timeout;                    // timeout left for client
}   clients [MAX_CLIENT];           // client table

int     chid;                       // channel ID (global)
int     debug = 1;                  // set debug value, 1 == enabled, 0 == off
char    *progname = "time1.c";

// forward prototypes
static  void setupPulseAndTimer (void);
static  void gotAPulse (void);
static  void gotAMessage (int rcvid, ClientMessageT *msg);

int
main (void)                         // ignore command-line arguments
{
    int rcvid;                      // process ID of the sender
    MessageT msg;                   // the message itself

    if ((chid = ChannelCreate (0)) == -1) {
        fprintf (stderr, "%s:  couldn't create channel!\n", progname);
        perror (NULL);
        exit (EXIT_FAILURE);
    }

    // set up the pulse and timer
    setupPulseAndTimer ();

    // receive messages
    for (;;) {
        rcvid = MsgReceive (chid, &msg, sizeof (msg), NULL);

        // determine who the message came from
        if (rcvid == 0) {
            // production code should check "code" field...
            gotAPulse ();
        } else {
            gotAMessage (rcvid, &msg.msg);
        }
    }

    // you won't get here
    return (EXIT_SUCCESS);
}

/*
 *  setupPulseAndTimer
 *
 *  This routine is responsible for setting up a pulse so it
 *  sends a message with code MT_TIMER.  It then sets up a periodic
 *  timer that fires once per second.
*/

void
setupPulseAndTimer (void)
{
    timer_t             timerid;    // timer ID for timer
    struct sigevent     event;      // event to deliver
    struct itimerspec   timer;      // the timer data structure
    int                 coid;       // connection back to ourselves

    // create a connection back to ourselves
    coid = ConnectAttach (0, 0, chid, 0, 0);
    if (coid == -1) {
        fprintf (stderr, "%s:  couldn't ConnectAttach to self!\n", progname);
        perror (NULL);
        exit (EXIT_FAILURE);
    }

    // set up the kind of event that we want to deliver -- a pulse
    SIGEV_PULSE_INIT (&event, coid, SIGEV_PULSE_PRIO_INHERIT, CODE_TIMER, 0);

    // create the timer, binding it to the event
    if (timer_create (CLOCK_REALTIME, &event, &timerid) == -1) {
        fprintf (stderr, "%s:  couldn't create a timer, errno %d\n", 
                 progname, errno);
        perror (NULL);
        exit (EXIT_FAILURE);
    }

    // setup the timer (1s delay, 1s reload)
    timer.it_value.tv_sec = 1;
    timer.it_value.tv_nsec = 0;
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_nsec = 0;

    // and start it!
    timer_settime (timerid, 0, &timer, NULL);
}

/*
 *  gotAPulse
 *
 *  This routine is responsible for handling the fact that a timeout
 *  has occurred.  It runs through the list of clients to see
 *  which client has timed-out, and replies to it with a timed-out
 *  response.
 */

void
gotAPulse (void)
{
    ClientMessageT  msg;
    int             i;

    if (debug) {
        time_t  now;

        time (&now);
        printf ("Got a Pulse at %s", ctime (&now));
    }

    // prepare a response message
    msg.messageType = MT_TIMEDOUT;

    // walk down list of clients
    for (i = 0; i < MAX_CLIENT; i++) {

        // is this entry in use?
        if (clients [i].in_use) {

            // is it about to time out?
            if (--clients [i].timeout == 0) {

                // send a reply
                MsgReply (clients [i].rcvid, EOK, &msg, sizeof (msg));

                // entry no longer used
                clients [i].in_use = 0;
            }
        }
    }
}

/*
 *  gotAMessage
 *
 *  This routine is called whenever a message arrives.  We look at the
 *  type of message (either a "wait for data" message, or a "here's some
 *  data" message), and act accordingly.  For simplicity, we'll assume
 *  that there is never any data waiting.  See the text for more discussion
 *  about this.
*/

void
gotAMessage (int rcvid, ClientMessageT *msg)
{
    int i;

    // determine the kind of message that it is
    switch (msg -> messageType) {

    // client wants to wait for data
    case    MT_WAIT_DATA:

        // see if we can find a blank spot in the client table
        for (i = 0; i < MAX_CLIENT; i++) {

            if (!clients [i].in_use) {

                // found one -- mark as in use, save rcvid, set timeout
                clients [i].in_use = 1;
                clients [i].rcvid = rcvid;
                clients [i].timeout = 5;
                return;
            }
        }

        fprintf (stderr, "Table full, message from rcvid %d ignored, "
                         "client blocked\n", rcvid);
        break;

    // client with data
    case    MT_SEND_DATA:

        // see if we can find another client to reply to with this 
        // client's data
        for (i = 0; i < MAX_CLIENT; i++) {

            if (clients [i].in_use) {

                // found one -- reuse the incoming message as an 
                // outgoing message
                msg -> messageType = MT_OK;

                // reply to BOTH CLIENTS!
                MsgReply (clients [i].rcvid, EOK, msg, sizeof (*msg));
                MsgReply (rcvid, EOK, msg, sizeof (*msg));

                clients [i].in_use = 0;
                return;
            }
        }

        fprintf (stderr, "Table empty, message from rcvid %d ignored, "
                         "client blocked\n", rcvid);
        break;
    }
}

tp1.c

For more information about this program, see Controlling the number of threads.

/*
 *	tp1.c
 *
 *	Thread Pool Example (1)
 *
 *	1999 06 26 R. Krten
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/neutrino.h>
#include <sys/dispatch.h>

char *progname = "tp1";

void
tag (char *name)
{
	time_t	t;
	char	buffer [BUFSIZ];

	time (&t);
	strftime (buffer, BUFSIZ, "%T ", localtime (&t));
	printf ("%s %3d %-20.20s:  ", buffer, pthread_self (), name);
}
	                                     
THREAD_POOL_PARAM_T *
blockfunc (THREAD_POOL_PARAM_T *ctp)
{
	tag ("blockfunc"); printf ("ctp %p\n", ctp);
	tag ("blockfunc"); printf ("sleep (%d);\n", 15 * pthread_self ());
	sleep (pthread_self () * 15);
	tag ("blockfunc"); printf ("done sleep\n");
	tag ("blockfunc"); printf ("returning 0x%08X\n", 0x10000000 + pthread_self ());
	return ((void *) (0x10000000 + pthread_self ()));		// passed to handlerfunc
}

THREAD_POOL_PARAM_T *
contextalloc (THREAD_POOL_HANDLE_T *handle)
{
	tag ("contextalloc"); printf ("handle %p\n", handle);
	tag ("contextalloc"); printf ("returning 0x%08X\n", 0x20000000 + pthread_self ());
	return ((void *) (0x20000000 + pthread_self ()));		// passed to blockfunc
}

void
contextfree (THREAD_POOL_PARAM_T *param)
{
	tag ("contextfree"); printf ("param %p\n", param);
}

void
unblockfunc (THREAD_POOL_PARAM_T *ctp)
{
	tag ("unblockfunc"); printf ("ctp %p\n", ctp);
}

int
handlerfunc (THREAD_POOL_PARAM_T *ctp)
{
	static int i = 0;

	tag ("handlerfunc"); printf ("ctp %p\n", ctp);
	if (i++ > 15) {
		tag ("handlerfunc"); printf ("exceeded 15 operations, return 0\n");
		return (0);
	}
	tag ("handlerfunc"); printf ("sleep (%d)\n", pthread_self () * 25);
	sleep (pthread_self () * 25);
	tag ("handlerfunc"); printf ("done sleep\n");

/*
	i = 0;
	if (i++ & 1) {
		tag ("handlerfunc"); printf ("returning 0\n");
		return (0);
	} else {
*/
		tag ("handlerfunc"); printf ("returning 0x%08X\n", 0x30000000 + pthread_self ());
		return (0x30000000 + pthread_self ());
/*
	}
*/
}


main ()
{
	thread_pool_attr_t	tp_attr;
	void				*tpp;

	memset (&tp_attr, 0, sizeof (tp_attr));
	tp_attr.handle = (void *) 0x12345678;		// passed to contextalloc
	tp_attr.block_func = blockfunc;
	tp_attr.unblock_func = unblockfunc;
	tp_attr.context_alloc = contextalloc;
	tp_attr.context_free = contextfree;
	tp_attr.handler_func = handlerfunc;

	tp_attr.lo_water = 3;
	tp_attr.hi_water = 7;
	tp_attr.increment = 2;
	tp_attr.maximum = 10;

    tpp = thread_pool_create (&tp_attr, POOL_FLAG_USE_SELF);
    if (tpp == NULL) {
        fprintf (stderr, 
                 "%s:  can't thread_pool_create, errno %s\n",
                 progname, strerror (errno));
        exit (EXIT_FAILURE);
    }

	thread_pool_start (tpp);

	fprintf (stderr, "%s:  thread_pool_start returned; errno %s\n",
             progname, strerror (errno));
	sleep (3000);
	exit (EXIT_FAILURE);
}

tt1.c

For more information about this program, see Kernel timeouts with pthread_join().

/*
 * tt1.c
*/

#include <stdio.h>
#include <pthread.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/neutrino.h>

#define SEC_NSEC 1000000000LL // 1 billion nanoseconds in a second

void *
long_thread (void *notused)
{
    printf ("This thread runs for more than 10 seconds\n");
    sleep (20);
}

int
main (void) // ignore arguments
{
    uint64_t        timeout;
    struct sigevent event;
    int             rval;
    pthread_t       thread_id;

    // set up the event -- this can be done once
    
    // This or event.sigev_notify = SIGEV_UNBLOCK:
    SIGEV_UNBLOCK_INIT (&event);

    // create a thread
    pthread_create (&thread_id, NULL, long_thread, NULL);

    // set up for 10 second timeout
    timeout = 10LL * SEC_NSEC;

    TimerTimeout (CLOCK_REALTIME, _NTO_TIMEOUT_JOIN, &event, &timeout, NULL);

    rval = pthread_join (thread_id, NULL);
    if (rval == ETIMEDOUT) {
        printf ("Thread %d is still running after 10 seconds!\n",
                thread_id);
    }

    sleep (5);
    
   
    TimerTimeout (CLOCK_REALTIME, _NTO_TIMEOUT_JOIN, &event, &timeout, NULL);
    rval = pthread_join (thread_id, NULL);
    if (rval == ETIMEDOUT) {
        printf ("Thread %d is still running after 25 seconds (bad)!\n",
                thread_id);
    } else {
        printf ("Thread %d finished (expected!)\n", thread_id);
    }
}

Last modified: 2014-11-17



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus