1 /*
2  * TCP free fragment queue for ring buffer - tcp_rb_frag_queue.c/h
3  *
4  * EunYoung Jeong
5  *
6  * Part of this code borrows Click's simple queue implementation
7  *
8  * ============================== Click License =============================
9  *
10  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, subject to the conditions
15  * listed in the Click LICENSE file. These conditions include: you must
16  * preserve this copyright notice, and you cannot mention the copyright
17  * holders in advertising related to the Software without their permission.
18  * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
19  * notice is a summary of the Click LICENSE file; the license in that file is
20  * legally binding.
21  */
22 
23 #include "tcp_rb_frag_queue.h"
24 #include "debug.h"
25 
26 /*----------------------------------------------------------------------------*/
27 #ifndef _INDEX_TYPE_
28 #define _INDEX_TYPE_
29 typedef uint32_t index_type;
30 typedef int32_t signed_index_type;
31 #endif
32 /*---------------------------------------------------------------------------*/
33 struct rb_frag_queue
34 {
35 	index_type _capacity;
36 	volatile index_type _head;
37 	volatile index_type _tail;
38 
39 	struct fragment_ctx * volatile * _q;
40 };
41 /*----------------------------------------------------------------------------*/
42 static inline index_type
NextIndex(rb_frag_queue_t rb_fragq,index_type i)43 NextIndex(rb_frag_queue_t rb_fragq, index_type i)
44 {
45 	return (i != rb_fragq->_capacity ? i + 1: 0);
46 }
47 /*---------------------------------------------------------------------------*/
48 static inline index_type
PrevIndex(rb_frag_queue_t rb_fragq,index_type i)49 PrevIndex(rb_frag_queue_t rb_fragq, index_type i)
50 {
51 	return (i != 0 ? i - 1: rb_fragq->_capacity);
52 }
53 /*---------------------------------------------------------------------------*/
54 static inline void
RBFragMemoryBarrier(struct fragment_ctx * volatile frag,volatile index_type index)55 RBFragMemoryBarrier(struct fragment_ctx * volatile frag, volatile index_type index)
56 {
57 	__asm__ volatile("" : : "m" (frag), "m" (index));
58 }
59 /*---------------------------------------------------------------------------*/
60 rb_frag_queue_t
CreateRBFragQueue(int capacity)61 CreateRBFragQueue(int capacity)
62 {
63 	rb_frag_queue_t rb_fragq;
64 
65 	rb_fragq = (rb_frag_queue_t)calloc(1, sizeof(struct rb_frag_queue));
66 	if (!rb_fragq)
67 		return NULL;
68 
69 	rb_fragq->_q = (struct fragment_ctx **)
70 			calloc(capacity + 1, sizeof(struct fragment_ctx *));
71 	if (!rb_fragq->_q) {
72 		free(rb_fragq);
73 		return NULL;
74 	}
75 
76 	rb_fragq->_capacity = capacity;
77 	rb_fragq->_head = rb_fragq->_tail = 0;
78 
79 	return rb_fragq;
80 }
81 /*---------------------------------------------------------------------------*/
82 void
DestroyRBFragQueue(rb_frag_queue_t rb_fragq)83 DestroyRBFragQueue(rb_frag_queue_t rb_fragq)
84 {
85 	if (!rb_fragq)
86 		return;
87 
88 	if (rb_fragq->_q) {
89 		free((void *)rb_fragq->_q);
90 		rb_fragq->_q = NULL;
91 	}
92 
93 	free(rb_fragq);
94 }
95 /*---------------------------------------------------------------------------*/
96 int
RBFragEnqueue(rb_frag_queue_t rb_fragq,struct fragment_ctx * frag)97 RBFragEnqueue(rb_frag_queue_t rb_fragq, struct fragment_ctx *frag)
98 {
99 	index_type h = rb_fragq->_head;
100 	index_type t = rb_fragq->_tail;
101 	index_type nt = NextIndex(rb_fragq, t);
102 
103 	if (nt != h) {
104 		rb_fragq->_q[t] = frag;
105 		RBFragMemoryBarrier(rb_fragq->_q[t], rb_fragq->_tail);
106 		rb_fragq->_tail = nt;
107 		return 0;
108 	}
109 
110 	TRACE_ERROR("Exceed capacity of frag queue!\n");
111 	return -1;
112 }
113 /*---------------------------------------------------------------------------*/
114 struct fragment_ctx *
RBFragDequeue(rb_frag_queue_t rb_fragq)115 RBFragDequeue(rb_frag_queue_t rb_fragq)
116 {
117 	index_type h = rb_fragq->_head;
118 	index_type t = rb_fragq->_tail;
119 
120 	if (h != t) {
121 		struct fragment_ctx *frag = rb_fragq->_q[h];
122 		RBFragMemoryBarrier(rb_fragq->_q[h], rb_fragq->_head);
123 		rb_fragq->_head = NextIndex(rb_fragq, h);
124 		assert(frag);
125 
126 		return frag;
127 	}
128 
129 	return NULL;
130 }
131 /*---------------------------------------------------------------------------*/
132