151 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ////////////////////////////////////////////////////////////////////////////////
 | |
| //                                                                            //
 | |
| // File:           ring_buffer.h                                              //
 | |
| // Description:    circular buffer for unlocked exchange of data              //
 | |
| // Project:        WANProxy XTech                                             //
 | |
| // Author:         Andreu Vidal Bramfeld-Software                             //
 | |
| // Last modified:  2015-04-01                                                 //
 | |
| //                                                                            //
 | |
| ////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifndef	COMMON_RING_BUFFER_H
 | |
| #define	COMMON_RING_BUFFER_H
 | |
| 
 | |
| #define STANDARD_RING_BUFFER_CAPACITY  32768
 | |
| #define ITEM_SIZE  ((int) sizeof (T))
 | |
| 
 | |
| template<typename T, int N = STANDARD_RING_BUFFER_CAPACITY> class RingBuffer
 | |
| {
 | |
| private:
 | |
|    unsigned char  buffer[N * ITEM_SIZE];
 | |
|    unsigned char* reader;
 | |
|    unsigned char* writer;
 | |
|    
 | |
| public:
 | |
|    RingBuffer ();
 | |
| 	
 | |
|    int read (T& trg);
 | |
|    int write (const T& src);
 | |
| 	
 | |
| 	bool is_empty ()   { return (reader == writer); }
 | |
| 	int data_size ()   { return (writer >= reader ? writer - reader : sizeof buffer - (reader - writer)); }
 | |
| };
 | |
|    
 | |
| template<typename T, int N> RingBuffer<T, N>::RingBuffer () 
 | |
| { 
 | |
|    reader = writer = buffer; 
 | |
| }
 | |
| 
 | |
| template<typename T, int N> int RingBuffer<T, N>::read (T& trg) 
 | |
| {
 | |
|    unsigned char* r;
 | |
|    unsigned char* w;
 | |
|    int s, t, n1, n2;
 | |
| 
 | |
|    r = reader;
 | |
|    w = writer;
 | |
|    s = (w >= r ? (w - r) : sizeof buffer - (r - w));
 | |
|    if (s >= ITEM_SIZE)
 | |
|    {
 | |
| 		t = buffer + sizeof buffer - r;
 | |
| 		if (ITEM_SIZE <= t)
 | |
| 			n1 = ITEM_SIZE, n2 = 0;
 | |
| 		else 
 | |
| 			n1 = t, n2 = ITEM_SIZE - t;
 | |
| 		memcpy (&trg, r, n1);
 | |
| 		if (n2)
 | |
| 			memcpy (((char*) &trg) + n1, buffer, n2);
 | |
| 		reader = (ITEM_SIZE < t ? r + n1 : buffer + n2);
 | |
| 		return ITEM_SIZE;
 | |
|    }
 | |
|    
 | |
|    return 0;
 | |
| }
 | |
|    
 | |
| template<typename T, int N> int RingBuffer<T, N>::write (const T& src) 
 | |
| {
 | |
|    unsigned char* r;
 | |
|    unsigned char* w;
 | |
|    int s, t, n1, n2;
 | |
|    
 | |
|    r = reader;
 | |
|    w = writer;
 | |
|    s = (w >= r ? sizeof buffer - (w - r) : (r - w));
 | |
|    if (s > ITEM_SIZE)
 | |
|    {
 | |
|       t = buffer + sizeof buffer - w;
 | |
|       if (ITEM_SIZE <= t)
 | |
|          n1 = ITEM_SIZE, n2 = 0;
 | |
|       else 
 | |
|          n1 = t, n2 = ITEM_SIZE - t;
 | |
|       memcpy (w, &src, n1);
 | |
|       if (n2)
 | |
|          memcpy (buffer, ((const char*) &src) + n1, n2);
 | |
|       writer = (ITEM_SIZE < t ? w + n1 : buffer + n2);
 | |
|       return ITEM_SIZE;
 | |
|    }
 | |
|    
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
 | |
| 
 | |
| #include <pthread.h>
 | |
| 
 | |
| template<typename T> class WaitBuffer
 | |
| {
 | |
| private:
 | |
| 	RingBuffer<T> ring;
 | |
| 	pthread_mutex_t mutex;
 | |
| 	pthread_cond_t ready;
 | |
| 
 | |
| public:
 | |
|    WaitBuffer ();
 | |
|    ~WaitBuffer ();
 | |
| 	
 | |
|    int read (T& trg);
 | |
|    int write (const T& src);
 | |
| 	
 | |
| 	void wakeup ()		{ if (ring.is_empty ()) pthread_cond_signal (&ready); }
 | |
| };
 | |
|    
 | |
| template<typename T> WaitBuffer<T>::WaitBuffer () 
 | |
| {
 | |
| 	pthread_mutex_init (&mutex, 0);
 | |
| 	pthread_cond_init (&ready, 0);
 | |
| }
 | |
| 
 | |
| template<typename T> WaitBuffer<T>::~WaitBuffer () 
 | |
| {
 | |
| 	pthread_mutex_destroy (&mutex);
 | |
| 	pthread_cond_destroy (&ready);
 | |
| }
 | |
| 
 | |
| template<typename T> int WaitBuffer<T>::read (T& trg) 
 | |
| {
 | |
| 	if (ring.is_empty ())
 | |
| 	{
 | |
| 		pthread_mutex_lock (&mutex);
 | |
| 		if (ring.is_empty ())
 | |
| 			pthread_cond_wait (&ready, &mutex);
 | |
| 		pthread_mutex_unlock (&mutex);
 | |
| 	}
 | |
| 	
 | |
| 	return ring.read (trg);
 | |
| }
 | |
| 
 | |
| template<typename T> int WaitBuffer<T>::write (const T& src) 
 | |
| {
 | |
| 	int rsl = ring.write (src);
 | |
| 	
 | |
| 	if (rsl && ring.data_size () == ITEM_SIZE)
 | |
| 	{
 | |
| 		pthread_mutex_lock (&mutex);
 | |
| 		pthread_cond_signal (&ready);
 | |
| 		pthread_mutex_unlock (&mutex);
 | |
| 	}
 | |
| 	
 | |
| 	return rsl;
 | |
| }
 | |
| 
 | |
| #endif /* !COMMON_RING_BUFFER_H */
 |