1 /*
2 * TCP free send buffer queue - tcp_sb_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_sb_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 sb_queue
34 {
35 index_type _capacity;
36 volatile index_type _head;
37 volatile index_type _tail;
38
39 struct tcp_send_buffer * volatile * _q;
40 };
41 /*----------------------------------------------------------------------------*/
42 static inline index_type
NextIndex(sb_queue_t sq,index_type i)43 NextIndex(sb_queue_t sq, index_type i)
44 {
45 return (i != sq->_capacity ? i + 1: 0);
46 }
47 /*---------------------------------------------------------------------------*/
48 static inline index_type
PrevIndex(sb_queue_t sq,index_type i)49 PrevIndex(sb_queue_t sq, index_type i)
50 {
51 return (i != 0 ? i - 1: sq->_capacity);
52 }
53 /*---------------------------------------------------------------------------*/
54 static inline void
SBMemoryBarrier(struct tcp_send_buffer * volatile buf,volatile index_type index)55 SBMemoryBarrier(struct tcp_send_buffer * volatile buf, volatile index_type index)
56 {
57 __asm__ volatile("" : : "m" (buf), "m" (index));
58 }
59 /*---------------------------------------------------------------------------*/
60 sb_queue_t
CreateSBQueue(int capacity)61 CreateSBQueue(int capacity)
62 {
63 sb_queue_t sq;
64
65 sq = (sb_queue_t)calloc(1, sizeof(struct sb_queue));
66 if (!sq)
67 return NULL;
68
69 sq->_q = (struct tcp_send_buffer **)
70 calloc(capacity + 1, sizeof(struct tcp_send_buffer *));
71 if (!sq->_q) {
72 free(sq);
73 return NULL;
74 }
75
76 sq->_capacity = capacity;
77 sq->_head = sq->_tail = 0;
78
79 return sq;
80 }
81 /*---------------------------------------------------------------------------*/
82 void
DestroySBQueue(sb_queue_t sq)83 DestroySBQueue(sb_queue_t sq)
84 {
85 if (!sq)
86 return;
87
88 if (sq->_q) {
89 free((void *)sq->_q);
90 sq->_q = NULL;
91 }
92
93 free(sq);
94 }
95 /*---------------------------------------------------------------------------*/
96 int
SBEnqueue(sb_queue_t sq,struct tcp_send_buffer * buf)97 SBEnqueue(sb_queue_t sq, struct tcp_send_buffer *buf)
98 {
99 index_type h = sq->_head;
100 index_type t = sq->_tail;
101 index_type nt = NextIndex(sq, t);
102
103 if (nt != h) {
104 sq->_q[t] = buf;
105 SBMemoryBarrier(sq->_q[t], sq->_tail);
106 sq->_tail = nt;
107 return 0;
108 }
109
110 TRACE_ERROR("Exceed capacity of buf queue!\n");
111 return -1;
112 }
113 /*---------------------------------------------------------------------------*/
114 struct tcp_send_buffer *
SBDequeue(sb_queue_t sq)115 SBDequeue(sb_queue_t sq)
116 {
117 index_type h = sq->_head;
118 index_type t = sq->_tail;
119
120 if (h != t) {
121 struct tcp_send_buffer *buf = sq->_q[h];
122 SBMemoryBarrier(sq->_q[h], sq->_head);
123 sq->_head = NextIndex(sq, h);
124 assert(buf);
125
126 return buf;
127 }
128
129 return NULL;
130 }
131 /*---------------------------------------------------------------------------*/
132