view tests/testfifo.c @ 1481:c9e9f8a71946

Update to 3GPP TS 32.299 V15.7.0 (2019-06) Add AVPs: - 3GPP-OC-Rating-Group, Unsigned32, code 1321 - 3GPP-OC-Request-Type, Enumerated, code 1322 - 3GPP-OC-Specific-Reduction, Grouped, code 1320 - 3GPP-PS-Data-Off-Status-32.299, Enumerated, code 4406 - API-Content, UTF8String, code 1309 - API-Direction, Enumerated, code 1310 - API-Identifier, OctetString, code 1311 - API-Invocation-Timestamp, Time, code 1312 - API-Network-Service-Node, Enumerated, code 1315 - API-Result-Code, Unsigned32, code 1313 - API-Size, Unsigned64, code 1314 - APN-Rate-Control, Grouped, code 3933 - APN-Rate-Control-Downlink, Grouped, code 3934 - APN-Rate-Control-Uplink, Grouped, code 3935 - Access-Network-Info-Change, Grouped, code 4401 - Additional-Exception-Reports, Enumerated, code 3936 - Announcement-Identifier, Unsigned32, code 3905 - Announcement-Information, Grouped, code 3904 - Announcement-Order, Unsigned32, code 3906 - Announcing-PLMN-ID, UTF8String, code 4408 - Announcing-UE-HPLMN-Identifier, UTF8String, code 3426 - Announcing-UE-VPLMN-Identifier, UTF8String, code 3427 - Application-Specific-Data, OctetString, code 3458 - Authorised-QoS, UTF8String, code 849 - BSSID, UTF8String, code 2716 - Basic-Service-Code, Grouped, code 3411 - Bearer-Capability, OctetString, code 3412 - CN-Operator-Selection-Entity, Enumerated, code 3421 - CP-CIoT-EPS-Optimisation-Indicator, Enumerated, code 3930 - CPDT-Information, Grouped, code 3927 - Called-Identity, UTF8String, code 3916 - Called-Identity-Change, Grouped, code 3917 - Cellular-Network-Information, OctetString, code 3924 - Charging-Per-IP-CAN-Session-Indicator, Enumerated, code 4400 - Civic-Address-Information, UTF8String, code 1305 - Coverage-Info, Grouped, code 3459 - Coverage-Status, Enumerated, code 3428 - Discoveree-UE-HPLMN-Identifier, UTF8String, code 4402 - Discoveree-UE-VPLMN-Identifier, UTF8String, code 4403 - Discoverer-UE-HPLMN-Identifier, UTF8String, code 4404 - Discoverer-UE-VPLMN-Identifier, UTF8String, code 4405 - EPDG-Address, Address, code 3425 - Enhanced-Diagnostics, Grouped, code 3901 - Exposure-Function-API-Information, Grouped, code 1316 - FE-Identifier-List, UTF8String, code 4413 - Forwarding-Pending, Enumerated, code 3415 - IMS-Visited-Network-Identifier, UTF8String, code 2713 - ISUP-Cause, Grouped, code 3416 - ISUP-Cause-Diagnostics, OctetString, code 3422 - ISUP-Cause-Location, Unsigned32, code 3423 - ISUP-Cause-Value, Unsigned32, code 3424 - ISUP-Location-Number, OctetString, code 3414 - Instance-Id, UTF8String, code 3402 - Inter-UE-Transfer, Enumerated, code 3902 - Language, UTF8String, code 3914 - Layer-2-Group-ID, OctetString, code 3429 - Location-Info, Grouped, code 3460 - MBMS-Charged-Party, Enumerated, code 2323 - MSC-Address, OctetString, code 3417 - MTC-IWF-Address, Address, code 3406 - Monitored-PLMN-Identifier, UTF8String, code 3430 - Monitoring-Event-Configuration-Activity, Integer32, code 3919 - Monitoring-Event-Functionality, Integer32, code 3922 - Monitoring-Event-Information, Grouped, code 3921 - Monitoring-Event-Report-Data, Grouped, code 3920 - Monitoring-Event-Report-Number, Unsigned32, code 3923 - Monitoring-UE-HPLMN-Identifier, UTF8String, code 3431 - Monitoring-UE-Identifier, UTF8String, code 3432 - Monitoring-UE-VPLMN-Identifier, UTF8String, code 3433 - NIDD-Submission, Grouped, code 3928 - Network-Call-Reference-Number, OctetString, code 3418 - PC3-Control-Protocol-Cause, Integer32, code 3434 - PC3-EPC-Control-Protocol-Cause, Integer32, code 3435 - PC5-Radio-Technology, Enumerated, code 1300 - Play-Alternative, Enumerated, code 3913 - Privacy-Indicator, Enumerated, code 3915 - ProSe-3rd-Party-Application-ID, UTF8String, code 3440 - ProSe-Direct-Communication-Reception-Data-Container, Grouped, code 3461 - ProSe-Direct-Communication-Transmission-Data-Container, Grouped, code 3441 - ProSe-Direct-Discovery-Model, Enumerated, code 3442 - ProSe-Event-Type, Enumerated, code 3443 - ProSe-Function-IP-Address, Address, code 3444 - ProSe-Function-PLMN-Identifier, UTF8String, code 3457 - ProSe-Functionality, Enumerated, code 3445 - ProSe-Group-IP-Multicast-Address, Address, code 3446 - ProSe-Information, Grouped, code 3447 - ProSe-Range-Class, Enumerated, code 3448 - ProSe-Reason-For-Cancellation, Enumerated, code 3449 - ProSe-Request-Timestamp, Time, code 3450 - ProSe-Role-Of-UE, Enumerated, code 3451 - ProSe-Source-IP-Address, Address, code 3452 - ProSe-Target-Layer-2-ID, OctetString, code 4410 - ProSe-UE-ID, OctetString, code 3453 - ProSe-UE-to-Network-Relay-UE-ID, OctetString, code 4409 - Proximity-Alert-Indication, Enumerated, code 3454 - Proximity-Alert-Timestamp, Time, code 3455 - Proximity-Cancellation-Timestamp, Time, code 3456 - Quota-Indicator, Enumerated, code 3912 - RAN-End-Time, Time, code 1301 - RAN-Secondary-RAT-Usage-Report, Grouped, code 1302 - RAN-Start-Time, Time, code 1303 - Radio-Frequency, OctetString, code 3462 - Radio-Parameter-Set-Info, Grouped, code 3463 - Radio-Parameter-Set-Values, OctetString, code 3464 - Radio-Resources-Indicator, Integer32, code 3465 - Rate-Control-Max-Message-Size, Unsigned32, code 3937 - Rate-Control-Max-Rate, Unsigned32, code 3938 - Rate-Control-Time-Unit, Unsigned32, code 3939 - Reason-Header, UTF8String, code 3401 - Related-Change-Condition-Information, Grouped, code 3925 - Related-IMS-Charging-Identifier, UTF8String, code 2711 - Related-IMS-Charging-Identifier-Node, Address, code 2712 - Related-Trigger, Grouped, code 3926 - Relay-IP-address, Address, code 4411 - Requested-PLMN-Identifier, UTF8String, code 3436 - Requestor-PLMN-Identifier, UTF8String, code 3437 - Role-Of-ProSe-Function, Enumerated, code 3438 - Route-Header-Received, UTF8String, code 3403 - Route-Header-Transmitted, UTF8String, code 3404 - SCEF-Address, Address, code 1317 - SCS-AS-Address, Grouped, code 3940 - SCS-Address, Address, code 3941 - SCS-Realm, DiameterIdentity, code 3942 - SGi-PtP-Tunnelling-Method, Enumerated, code 3931 - SM-Device-Trigger-Indicator, Enumerated, code 3407 - SM-Device-Trigger-Information, Grouped, code 3405 - SM-Sequence-Number, Unsigned32, code 3408 - SMS-Result, Unsigned32, code 3409 - Secondary-RAT-Type, OctetString, code 1304 - Serving-Node-Identity, DiameterIdentity, code 3929 - Start-of-Charging, Time, code 3419 - TAD-Identifier, Enumerated, code 2717 - TLTRI, Unsigned32, code 1318 - TWAG-Address, Address, code 3903 - TWAN-User-Location-Info, Grouped, code 2714 - Target-IP-Address, Address, code 4412 - Teleservice, OctetString, code 3413 - Time-First-Reception, Time, code 3466 - Time-First-Transmission, Time, code 3467 - Time-Indicator, Unsigned32, code 3911 - Transmitter-Info, Grouped, code 3468 - UNI-PDU-CP-Only-Flag, Enumerated, code 3932 - UWAN-User-Location-Info, Grouped, code 3918 - Unused-Quota-Timer, Unsigned32, code 4407 - Usage-Information-Report-Sequence-Number, Integer32, code 3439 - VCS-Information, Grouped, code 3410 - VLR-Number, OctetString, code 3420 - Variable-Part, Grouped, code 3907 - Variable-Part-Order, Unsigned32, code 3908 - Variable-Part-Type, Unsigned32, code 3909 - Variable-Part-Value, UTF8String, code 3910 - WLAN-Operator-Id, Grouped, code 1306 - WLAN-Operator-Name, UTF8String, code 1307 - WLAN-PLMN-Id, UTF8String, code 1308 3GPP TS 32.299 V11.8.0 (2013-07) renamed LCS-Requestor-Id (1239) to LCS-Requestor-ID (1239). 3GPP TS 32.299 V11.8.0 (2013-07) renamed LCS-Requestor-Id-String (1240) to LCS-Requestor-ID-String (1240). 3GPP TS 32.299 V13.1.0 (2015-06) renamed PoC-User-Role-info-Units (1254) to PoC-User-Role-Info-Units (1254). 3GPP TS 32.299 V11.10.0 (2013-12) renamed Status (2702) to Status-Code (2702), and then 3GPP TS 32.299 V11.14.0 (2014-12) renamed Status-Code (2702) to Status-AS-Code (2702).
author Luke Mewburn <luke@mewburn.net>
date Thu, 26 Mar 2020 15:26:18 +1100
parents 1af09cc156d6
children
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
*													 *
* Copyright (c) 2013, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

#include "tests.h"
#include <unistd.h>
#include <limits.h>

/* Wrapper for pthread_barrier stuff on Mac OS X */
#ifndef HAVE_PTHREAD_BAR

#define PTHREAD_BARRIER_SERIAL_THREAD 1
typedef struct {
	int count;
	int entered;
	int serial;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
} pthread_barrier_t;

int pthread_barrier_init(pthread_barrier_t * barrier, int * barrier_attr, int count)
{
	memset(barrier, 0, sizeof(pthread_barrier_t));
	barrier->count = count;
	pthread_mutex_init(&barrier->mutex, NULL);
	pthread_cond_init(&barrier->cond, NULL);
	return 0;
}

int pthread_barrier_destroy(pthread_barrier_t * barrier)
{
	pthread_mutex_destroy(&barrier->mutex);
	pthread_cond_destroy(&barrier->cond);
	return 0;
}

int pthread_barrier_wait(pthread_barrier_t * barrier)
{
	int ret = 0;
	int serial;
	pthread_mutex_lock(&barrier->mutex);
	serial = barrier->serial;
	
	/* first thread gets the special value */
	if (barrier->entered++ == 0) 
		ret = PTHREAD_BARRIER_SERIAL_THREAD;
	
	/* Count was achieved? */
	if (barrier->entered == barrier->count) {
		/* Ok, increase serial, reset number of threads, and signal everyone */
		barrier->entered = 0;
		barrier->serial++;
		pthread_cond_broadcast(&barrier->cond);
	} else {
		do {
			pthread_cond_wait(&barrier->cond, &barrier->mutex);
		} while (barrier->serial == serial);
		/* this protects against spurious wakes */
	}
	pthread_mutex_unlock(&barrier->mutex);
	return 0;
}

#endif /* HAVE_PTHREAD_BAR */

/* Structure for testing threshold function */
static struct thrh_test {
	struct fifo *   queue; /* pointer to the queue */
	int		h_calls; /* number of calls of h_cb */
	int		l_calls; /* number of calls of l_cb */
} thrh_td;

/* Callbacks for threasholds test */
void thrh_cb_h(struct fifo *queue, void **data)
{
	if (thrh_td.h_calls == thrh_td.l_calls) {
		CHECK( NULL, *data );
		*data = &thrh_td;
	} else {
		CHECK( *data, &thrh_td );
	}
	CHECK( queue, thrh_td.queue );
	
	/* Update the count */
	thrh_td.h_calls ++;
}
void thrh_cb_l(struct fifo *queue, void **data)
{
	CHECK( 1, data ? 1 : 0 );
	CHECK( *data, &thrh_td );

	/* Check the queue parameter is correct */
	CHECK( queue, thrh_td.queue );
	
	/* Update the count */
	thrh_td.l_calls ++;
	/* Cleanup the data ptr if needed */
	if (thrh_td.l_calls == thrh_td.h_calls)
		*data = NULL;
	/* done */
}


/* Structure that is passed to the test function */
struct test_data {
	struct fifo     * queue; /* pointer to the queue */
	pthread_barrier_t * bar;   /* if not NULL, barrier to synchronize before getting messages */
	struct timespec   * ts;	   /* if not NULL, use a timedget instead of a get */
	int		    nbr;   /* number of messages to retrieve from the queue */
};

/* The test function, to be threaded */
static void * test_fct(void * data)
{
	int ret = 0, i;
	struct msg * msg = NULL;
	struct test_data * td = (struct test_data *) data;
	
	if (td->bar != NULL) {
		ret = pthread_barrier_wait(td->bar);
		if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
			CHECK( 0, ret);
		} else {
			CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */
		}
	}
	
	for (i=0; i< td->nbr; i++) {
		if (td->ts != NULL) {
			CHECK( 0, fd_fifo_timedget(td->queue, &msg, td->ts) );
		} else {
			CHECK( 0, fd_fifo_get(td->queue, &msg) );
		}
	}
	
	return NULL;
}

/* The test function, to be threaded */
static int iter  = 0;
static void * test_fct2(void * data)
{
	int i;
	int * item;
	struct test_data * td = (struct test_data *) data;
	
	for (i=0; i< td->nbr; i++) {
		item = malloc(sizeof(int));
		CHECK( 1, item ? 1 : 0 );
		*item = i;
		CHECK( 0, fd_fifo_post(td->queue, &item) );
		iter++;
	}
	
	return NULL;
}


/* Main test routine */
int main(int argc, char *argv[])
{
	struct timespec ts;
	
	struct msg * msg1 = NULL;
	struct msg * msg2 = NULL;
	struct msg * msg3 = NULL;
	
	/* First, initialize the daemon modules */
	INIT_FD();
	
	/* Prolog: create the messages */
	{
		struct dict_object * acr_model = NULL;
		struct dict_object * cer_model = NULL;
		struct dict_object * dwr_model = NULL;

		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", 			&acr_model, ENOENT ) );
		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", 	&cer_model, ENOENT ) );
		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request",		&dwr_model, ENOENT ) );
		CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) );
		CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) );
		CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) );
	}
	
	/* Basic operation */
	{
		struct fifo * queue = NULL;
		struct msg * msg  = NULL;
		int max;
		long long count;
		
		/* Create the queue */
		CHECK( 0, fd_fifo_new(&queue, 0) );
		
		/* Check the count is 0 */
		CHECK( 0, fd_fifo_length(queue) );
		
		/* Now enqueue */
		msg = msg1;
		CHECK( 0, fd_fifo_post(queue, &msg) );
		msg = msg2;
		CHECK( 0, fd_fifo_post(queue, &msg) );
		msg = msg3;
		CHECK( 0, fd_fifo_post(queue, &msg) );
		
		/* Check the count is 3 */
		CHECK( 3, fd_fifo_length(queue) );
		
		/* Retrieve the first message using fd_fifo_get */
		CHECK( 0, fd_fifo_get(queue, &msg) );
		CHECK( msg1, msg);
		CHECK( 2, fd_fifo_length(queue) );
		
		/* Retrieve the second message using fd_fifo_timedget */
		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
		ts.tv_sec += 1; /* Set the timeout to 1 second */
		CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) );
		CHECK( msg2, msg);
		CHECK( 1, fd_fifo_length(queue) );
		
		/* Retrieve the third message using meq_tryget */
		CHECK( 0, fd_fifo_tryget(queue, &msg) );
		CHECK( msg3, msg);
		CHECK( 0, fd_fifo_length(queue) );
		
		/* Check that another meq_tryget does not block */
		CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) );
		CHECK( 0, fd_fifo_length(queue) );
		
		/* Check the timedget actually timesout */
		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
		ts.tv_nsec += 1000000; /* 1 millisecond */
		if (ts.tv_nsec >= 1000000000L) {
			ts.tv_nsec -= 1000000000L;
			ts.tv_sec += 1;
		}
		CHECK( ETIMEDOUT, fd_fifo_timedget(queue, &msg, &ts) );
		CHECK( 0, fd_fifo_length(queue) );
		
		/* Post & get another message */
		msg = msg1;
		CHECK( 0, fd_fifo_post(queue, &msg) );
		CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) );
		CHECK( msg1, msg);		
		
		/* Check some statistics */
		CHECK( 0, fd_fifo_getstats(queue, NULL, NULL, &max, &count, NULL, NULL, NULL) );
		CHECK( 3, max );
		CHECK( 4, count );	
		
		/* We're done for basic tests */
		CHECK( 0, fd_fifo_del(&queue) );
	}
	
	/* Test robustness, ensure no messages are lost */
	{
#define NBR_MSG		200
#define NBR_THREADS	60
		struct fifo  		*queue = NULL;
		pthread_barrier_t	 bar;
		struct test_data	 td_1;
		struct test_data	 td_2;
		struct msg   		*msgs[NBR_MSG * NBR_THREADS * 2], *msg;
		pthread_t  		 thr [NBR_THREADS * 2];
		struct dict_object	*dwr_model = NULL;
		int			 i;
		int			 nbr_threads;
#ifdef _POSIX_THREAD_THREADS_MAX
		nbr_threads = _POSIX_THREAD_THREADS_MAX;
#else /* _POSIX_THREAD_THREADS_MAX */
		nbr_threads = sysconf(_SC_THREAD_THREADS_MAX);
#endif /* _POSIX_THREAD_THREADS_MAX */
		if ((nbr_threads <= 0) || (nbr_threads > NBR_THREADS * 2)) {
			nbr_threads = NBR_THREADS;
		} else {
			TRACE_DEBUG(INFO, "Local limit on number of threads: %d", nbr_threads);
			/* The local limit is below NBR_THREADS */
			nbr_threads = (nbr_threads / 2) - 1;
			/* Ensure we create at least a few threads! */
			CHECK( 1, nbr_threads >= 10 ? 1 : 0 );
		}
		
		/* Create the queue */
		CHECK( 0, fd_fifo_new(&queue, 0) );
		
		/* Create the barrier */
		CHECK( 0, pthread_barrier_init(&bar, NULL, nbr_threads * 2 + 1) );
		
		/* Initialize the ts */
		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
		ts.tv_sec += 20; /* Set the timeout to 20 second */
		
		/* Create the messages */
		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request",		&dwr_model, ENOENT ) );
		for (i = 0; i < NBR_MSG * nbr_threads * 2; i++) {
			CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) );
		}
		
		/* Initialize the test data structures */
		td_1.queue = queue;
		td_1.bar = &bar;
		td_1.ts  = &ts;
		td_1.nbr = NBR_MSG;
		td_2.queue = queue;
		td_2.bar = &bar;
		td_2.ts  = NULL;
		td_2.nbr = NBR_MSG;
		
		/* Create the threads */
		for (i=0; i < nbr_threads * 2; i++) {
			CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) );
		}
		
		/* Synchronize everyone */
		{
			int ret = pthread_barrier_wait(&bar);
			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
				CHECK( 0, ret);
			} else {
				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */
			}
		}
		
		/* Now post all the messages */
		for (i=0; i < NBR_MSG * nbr_threads * 2; i++) {
			msg = msgs[i];
			CHECK( 0, fd_fifo_post(queue, &msg) );
		}
		
		/* Join all threads. This blocks if messages are lost... */
		for (i=0; i < nbr_threads * 2; i++) {
			CHECK( 0, pthread_join( thr[i], NULL ) );
		}
		
		/* Check the count of the queue is back to 0 */
		CHECK( 0, fd_fifo_length(queue) );
		
		/* Destroy this queue and the messages */
		CHECK( 0, fd_fifo_del(&queue) );
		for (i=0; i < NBR_MSG * nbr_threads * 2; i++) {
			CHECK( 0, fd_msg_free(  msgs[i] ) );
		}
	}
	
	/* Test thread cancelation */
	{
		struct fifo      	*queue = NULL;
		pthread_barrier_t	 bar;
		struct test_data	 td;
		pthread_t		 th;
		
		/* Create the queue */
		CHECK( 0, fd_fifo_new(&queue, 0) );
		
		/* Create the barrier */
		CHECK( 0, pthread_barrier_init(&bar, NULL, 2) );
		
		/* Initialize the ts */
		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
		ts.tv_sec += 10; /* Set the timeout to 10 second */
		
		/* Initialize the test data structures */
		td.queue = queue;
		td.bar = &bar;
		td.ts  = &ts;
		td.nbr = 1;
		
		/* Create the thread */
		CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
		
		/* Wait for the thread to be running */
		{
			int ret = pthread_barrier_wait(&bar);
			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
				CHECK( 0, ret);
			} else {
				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
			}
		}
		
		/* Now cancel the thread */
		CHECK( 0, pthread_cancel( th ) );
		
		/* Join it */
		CHECK( 0, pthread_join( th, NULL ) );
		
		/* Do the same with the other function */
		td.ts  = NULL;
		
		/* Create the thread */
		CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
		
		/* Wait for the thread to be running */
		{
			int ret = pthread_barrier_wait(&bar);
			if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
				CHECK( 0, ret);
			} else {
				CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
			}
		}
		
		/* Now cancel the thread */
		CHECK( 0, pthread_cancel( th ) );
		
		/* Join it */
		CHECK( 0, pthread_join( th, NULL ) );
		
		/* Destroy the queue */
		CHECK( 0, fd_fifo_del(&queue) );
	}
	
	/* Test the threashold function */
	{
		struct fifo * queue = NULL;
		int i;
		struct msg * msg  = NULL;
		
		/* Create the queue */
		CHECK( 0, fd_fifo_new(&queue, 0) );
		
		/* Prepare the test data */
		memset(&thrh_td, 0, sizeof(thrh_td));
		thrh_td.queue = queue;
		
		/* Set the thresholds for the queue */
		CHECK( 0, fd_fifo_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) );
		
		/* Post 5 messages, no cb must be called. */
		for (i=0; i<5; i++) {
			msg = msg1;
			CHECK( 0, fd_fifo_post(queue, &msg) );
		} /* 5 msg in queue */
		CHECK( 0, thrh_td.h_calls );
		CHECK( 0, thrh_td.l_calls );
		
		/* Get all these messages, and check again */
		for (i=0; i<5; i++) {
			CHECK( 0, fd_fifo_get(queue, &msg) );
		} /* 0 msg in queue */
		CHECK( 0, thrh_td.h_calls );
		CHECK( 0, thrh_td.l_calls );
		
		/* Now, post 6 messages, the high threashold */
		for (i=0; i<6; i++) {
			msg = msg1;
			CHECK( 0, fd_fifo_post(queue, &msg) );
		} /* 6 msg in queue */
		CHECK( 1, thrh_td.h_calls );
		CHECK( 0, thrh_td.l_calls );
		
		/* Remove 2 messages, to reach the low threshold */
		for (i=0; i<2; i++) {
			CHECK( 0, fd_fifo_get(queue, &msg) );
		} /* 4 msg in queue */
		CHECK( 1, thrh_td.h_calls );
		CHECK( 1, thrh_td.l_calls );
		
		/* Come again at the high threshold */
		for (i=0; i<2; i++) {
			msg = msg1;
			CHECK( 0, fd_fifo_post(queue, &msg) );
		} /* 6 msg in queue */
		CHECK( 2, thrh_td.h_calls );
		CHECK( 1, thrh_td.l_calls );
		
		/* Suppose the queue continues to grow */
		for (i=0; i<6; i++) {
			msg = msg1;
			CHECK( 0, fd_fifo_post(queue, &msg) );
		} /* 12 msg in queue */
		CHECK( 3, thrh_td.h_calls );
		CHECK( 1, thrh_td.l_calls );
		for (i=0; i<5; i++) {
			msg = msg1;
			CHECK( 0, fd_fifo_post(queue, &msg) );
		} /* 17 msg in queue */
		CHECK( 3, thrh_td.h_calls );
		CHECK( 1, thrh_td.l_calls );
		
		/* Now the queue goes back to 0 messages */
		for (i=0; i<17; i++) {
			CHECK( 0, fd_fifo_get(queue, &msg) );
		} /* 0 msg in queue */
		CHECK( 3, thrh_td.h_calls );
		CHECK( 3, thrh_td.l_calls );
		
		/* We're done for this test */
		CHECK( 0, fd_fifo_del(&queue) );
	}
	
	/* Test max queue limit */
	{
		struct fifo      	*queue = NULL;
		struct test_data	 td;
		pthread_t		 th;
		int *			item, i;
		
		/* Create the queue */
		CHECK( 0, fd_fifo_new(&queue, 10) );
		
		/* Initialize the test data structures */
		td.queue = queue;
		td.nbr = 15;
		
		CHECK( 0, pthread_create( &th, NULL, test_fct2, &td ) );
		
		usleep(100000); /* 100 millisec */
		
		CHECK( 10, iter );
		
		CHECK( 0, fd_fifo_tryget(queue, &item) );
		CHECK( 0, *item);
		free(item);
		
		usleep(100000); /* 100 millisec */
		
		CHECK( 11, iter );
		
		for (i=1; i<4; i++) {
			CHECK( 0, fd_fifo_get(queue, &item) );
			CHECK( i, *item);
			free(item);
		}
		
		usleep(100000); /* 100 millisec */
		
		CHECK( 14, iter );
		
		for (; i < td.nbr; i++) {
			CHECK( 0, fd_fifo_tryget(queue, &item) );
			CHECK( i, *item);
			free(item);
		}
		
		CHECK( 0, pthread_join( th, NULL ) );
		CHECK( 15, iter );
		
	}
	
	/* Delete the messages */
	CHECK( 0, fd_msg_free( msg1 ) );
	CHECK( 0, fd_msg_free( msg2 ) );
	CHECK( 0, fd_msg_free( msg3 ) );

	/* That's all for the tests yet */
	PASSTEST();
} 
"Welcome to our mercurial repository"