/* Check base speed of MST creation/deletion
 * Usage:
 *	testmst iterations [concurrency] [stacksize]
 *
 * If fname present, file is opened each iteration.
 *      
 */

#include <stdio.h>
#include <stdlib.h>
#include "pthread_1c_np.h"
#include "tutil.h"
#include "message_service.h"
static int max_ndx = 0;
static pthread_mutex_t ndx_lock;
int http_reentrant_c_rtl;
int (* tlog_putlog_cb) (int, char * );
/*
 * Echo_message MST simply reads and returns read data.
 */
int echo_message ( mst_link_t link, char *service,
	char *info, int ndx, int avail )
{
    int size, status, written;
    char buffer[2000];
    pthread_mutex_lock ( &ndx_lock );
    if ( ndx > max_ndx ) max_ndx = ndx;
    pthread_mutex_unlock ( &ndx_lock );
    while ( 1&mst_read ( link, buffer, sizeof(buffer), &size ) ) {
#ifdef ECHO_RESPONSE
	status = mst_write ( link, buffer, size, &written );
	if ( (1&status) == 0 ) break;
#endif
    }
    mst_close ( link );
    return 1;
}
/*
 * Discard MST is a simple sink for incoming messages.
 */
int discard_message ( mst_link_t link, char *service,
	char *info, int ndx, int avail )
{
    int size, status, written;
    char buffer[2000];
    pthread_mutex_lock ( &ndx_lock );
    if ( ndx > max_ndx ) max_ndx = ndx;
    pthread_mutex_unlock ( &ndx_lock );
    while ( 1&mst_read ( link, buffer, sizeof(buffer), &size ) ) {
    }
    mst_close ( link );
    return 1;
}
int tlog_putlog ( int level, char *fmt ) { return 0; }

int main ( int argc, char **argv )
{
    int status, size, iterations, i, lnum, io_size, concurrency, pool_id;
    int LIB$INIT_TIMER(), LIB$SHOW_TIMER();
    mst_link_t link[1024];
    char *envval, buffer[20000];
    pthread_attr_t attr;
    
    envval = getenv("HTTP_REENTRANT_C_RTL");
    tlog_putlog_cb = &tlog_putlog;
#ifdef __DECC
    http_reentrant_c_rtl = envval ? atoi ( envval ) : 1;
    if ( http_reentrant_c_rtl ) {
        decc$set_reentrancy ( C$C_MULTITHREAD );
        printf("Set DECC library for multi-thread use!/" );
    }
#else
    http_reentrant_c_rtl = envval ? atoi ( envval ) : 0;
#endif
    iterations=1000;
    if ( argc > 1 ) iterations = atoi(argv[1]);
    io_size = 100;
    concurrency = 1;
    if ( argc > 2 ) concurrency = atoi(argv[2]);
    printf("Iterations: %d, concurrency: %d\n", iterations, concurrency );
    if ( concurrency > 1024 ) concurrency = 1024;
    INITIALIZE_THREAD_ATTR(&attr);
    if ( argc > 3 ) {
	int stacksize;
	stacksize = atoi ( argv[3] );
	printf("Setting stack size to %d\n", stacksize );
	pthread_attr_setstacksize ( &attr, stacksize );
    }
    /*
     * Create services.
     */
    pool_id = 0;
    status = mst_create_service_pool ( attr, concurrency*2+10, 1, &pool_id );
    printf("Created pool, status: %d\n", pool_id );
	
    status = mst_register_service ( "echo", echo_message, "test", pool_id );
    printf("Registered service 'echo', status: %d\n", status );

    status = mst_register_service ( "sink", discard_message, "test", pool_id );
    printf("Registered service 'sink', status: %d\n", status );
    /*
     * Timing loop.
     */
    for ( i = 0; i < concurrency; i++ ) link[i] = (mst_link_t) 0;
    LIB$INIT_TIMER();
    for ( i = 0; i < iterations; i++ ) {
	lnum = i % concurrency;
	if ( i > concurrency ) {
	    status = mst_close ( link[lnum] );
	}
	status = mst_connect ( "echo", "dummy", &link[lnum] );
	if ( (status&1) == 0 ) {
	    printf("Error in connect[%d(%d)]: %d\n", i, lnum, status );
	} else {
	    status = mst_write ( link[lnum], buffer, 200, &size );
#ifdef ECHO_RESPONSE
	    if ( status&1 ) status = mst_read ( 
		link[lnum], buffer, sizeof(buffer), &size );
#endif
	}
	if ( (status&1) == 0 ) break;
    }
    for ( i = 0; i < concurrency; i++ ) if ( link[i] ) {
	status = mst_close ( link[i] );
    }
    LIB$SHOW_TIMER();
    printf("Max thread index: %d\n", max_ndx );
    return 1;
}

