12
12
* new string. When new item is added then first it is compared if it is not
13
13
* the same as the last one (then it is not stored). If there is no room in the
14
14
* buffer to store the new item, oldest one is removed until there is a room.
15
- *
16
- * Items are allocated and stored in the ring buffer. Items then a linked in
17
- * the list.
18
- *
19
- * Because stored strings must be copied and compared, it is more convenient to
20
- * store them in the ring buffer in a way that they are not split into two
21
- * chunks (when ring buffer wraps). To ensure that item is in a single chunk,
22
- * item includes padding. If continues area for new item cannot be allocated
23
- * then allocated space is increased by the padding.
24
- *
25
- * If item does not fit at the end of the ring buffer padding is added: *
26
- * +-----------+----------------+-----------------------------------+---------+
27
- * | header | "history item" | | padding |
28
- * | padding | | | |
29
- * +-----------+----------------+-----------------------------------+---------+
30
- *
31
- * If item fits in the ring buffer available space then there is no padding:
32
- * +-----------------+------------+----------------+--------------------------+
33
- * | | header | "history item" | |
34
- * | | no padding | | |
35
- * +-----------------+------------+----------------+--------------------------+
36
- *
37
- * As an optimization, the added padding is attributed to the preceding item
38
- * instead of the current item. This way the padding will be freed one item
39
- * sooner.
40
15
*/
16
+
41
17
struct shell_history_item {
42
18
sys_dnode_t dnode ;
43
19
uint16_t len ;
44
- uint16_t padding ;
45
20
char data [];
46
21
};
47
22
@@ -56,72 +31,40 @@ bool z_shell_history_get(struct shell_history *history, bool up,
56
31
struct shell_history_item * h_item ; /* history item */
57
32
sys_dnode_t * l_item ; /* list item */
58
33
59
- if (sys_dlist_is_empty (& history -> list )) {
60
- * len = 0U ;
61
- return false;
62
- }
63
-
64
- if (!up ) { /* button down */
65
- if (history -> current == NULL ) {
66
- /* Not in history mode. It is started by up button. */
67
- * len = 0U ;
68
-
69
- return false;
70
- }
71
-
72
- l_item = sys_dlist_peek_prev_no_check (& history -> list ,
73
- history -> current );
74
- } else { /* button up */
34
+ if (up ) { /* button up */
75
35
l_item = (history -> current == NULL ) ?
76
- sys_dlist_peek_head_not_empty (& history -> list ) :
36
+ sys_dlist_peek_head (& history -> list ) :
77
37
sys_dlist_peek_next_no_check (& history -> list , history -> current );
38
+ } else { /* button down */
39
+ l_item = sys_dlist_peek_prev (& history -> list , history -> current );
40
+ }
78
41
42
+ if (l_item == NULL ) {
43
+ /* Reached the end of history. */
44
+ * len = 0U ;
45
+ return false;
79
46
}
80
47
81
48
history -> current = l_item ;
82
49
h_item = CONTAINER_OF (l_item , struct shell_history_item , dnode );
83
-
84
- if (l_item ) {
85
- memcpy (dst , h_item -> data , h_item -> len );
86
- * len = h_item -> len ;
87
- dst [* len ] = '\0' ;
88
- return true;
89
- }
90
-
91
- * len = 0U ;
92
- return false;
93
- }
94
-
95
- static void add_to_head (struct shell_history * history ,
96
- struct shell_history_item * item ,
97
- uint8_t * src , size_t len , uint16_t padding )
98
- {
99
- item -> len = len ;
100
- item -> padding = padding ;
101
- memcpy (item -> data , src , len );
102
- sys_dlist_prepend (& history -> list , & item -> dnode );
50
+ memcpy (dst , h_item -> data , h_item -> len );
51
+ * len = h_item -> len ;
52
+ dst [* len ] = '\0' ;
53
+ return true;
103
54
}
104
55
105
56
/* Returns true if element was removed. */
106
57
static bool remove_from_tail (struct shell_history * history )
107
58
{
108
- sys_dnode_t * l_item ; /* list item */
109
- struct shell_history_item * h_item ;
110
- uint32_t total_len ;
59
+ sys_dnode_t * node ;
111
60
112
61
if (sys_dlist_is_empty (& history -> list )) {
113
62
return false;
114
63
}
115
64
116
- l_item = sys_dlist_peek_tail (& history -> list );
117
- sys_dlist_remove (l_item );
118
-
119
- h_item = CONTAINER_OF (l_item , struct shell_history_item , dnode );
120
-
121
- total_len = offsetof(struct shell_history_item , data ) +
122
- h_item -> len + h_item -> padding ;
123
- ring_buf_get (history -> ring_buf , NULL , total_len );
124
-
65
+ node = sys_dlist_peek_tail (& history -> list );
66
+ sys_dlist_remove (node );
67
+ k_heap_free (history -> heap , CONTAINER_OF (node , struct shell_history_item , dnode ));
125
68
return true;
126
69
}
127
70
@@ -134,77 +77,39 @@ void z_shell_history_purge(struct shell_history *history)
134
77
void z_shell_history_put (struct shell_history * history , uint8_t * line ,
135
78
size_t len )
136
79
{
137
- sys_dnode_t * l_item ; /* list item */
138
- struct shell_history_item * h_item , * h_prev_item ;
80
+ sys_dnode_t * node ;
81
+ struct shell_history_item * new , * h_prev_item ;
139
82
uint32_t total_len = len + offsetof(struct shell_history_item , data );
140
- uint32_t claim_len ;
141
- uint32_t claim2_len ;
142
- uint16_t padding = (~total_len + 1 ) & (sizeof (void * ) - 1 );
143
-
144
- /* align to word. */
145
- total_len += padding ;
146
-
147
- if (total_len > ring_buf_capacity_get (history -> ring_buf )) {
148
- return ;
149
- }
150
83
151
84
z_shell_history_mode_exit (history );
152
-
153
85
if (len == 0 ) {
154
86
return ;
155
87
}
156
88
157
- l_item = sys_dlist_peek_head (& history -> list );
158
- h_prev_item = CONTAINER_OF (l_item , struct shell_history_item , dnode );
89
+ node = sys_dlist_peek_head (& history -> list );
90
+ h_prev_item = CONTAINER_OF (node , struct shell_history_item , dnode );
159
91
160
- if (l_item &&
92
+ if (node &&
161
93
(h_prev_item -> len == len ) &&
162
94
(memcmp (h_prev_item -> data , line , len ) == 0 )) {
163
95
/* Same command as before, do not store */
164
96
return ;
165
97
}
166
98
167
- do {
168
- if (ring_buf_is_empty (history -> ring_buf )) {
169
- /* if history is empty reset ring buffer. Even when
170
- * ring buffer is empty, it is possible that available
171
- * continues memory in worst case equals half of the
172
- * ring buffer capacity. By resetting ring buffer we
173
- * ensure that it is capable to provide continues memory
174
- * of ring buffer capacity length.
175
- */
176
- ring_buf_reset (history -> ring_buf );
177
- }
178
-
179
- claim_len = ring_buf_put_claim (history -> ring_buf ,
180
- (uint8_t * * )& h_item , total_len );
181
- /* second allocation may succeed if we were at the end of the
182
- * buffer.
183
- */
184
- if (claim_len < total_len ) {
185
- claim2_len =
186
- ring_buf_put_claim (history -> ring_buf ,
187
- (uint8_t * * )& h_item , total_len );
188
- if (claim2_len == total_len ) {
189
- /*
190
- * We may get here only if a previous entry
191
- * exists. Stick the excess padding to it.
192
- */
193
- h_prev_item -> padding += claim_len ;
194
- total_len += claim_len ;
195
- claim_len = total_len ;
196
- }
197
- }
198
-
199
- if (claim_len == total_len ) {
200
- add_to_head (history , h_item , line , len , padding );
201
- ring_buf_put_finish (history -> ring_buf , claim_len );
99
+ for (;;) {
100
+ new = k_heap_alloc (history -> heap , total_len , K_NO_WAIT );
101
+ if (new ) {
102
+ /* Got memory, add new item */
202
103
break ;
104
+ } else if (!remove_from_tail (history )) {
105
+ /* Nothing to remove, cannot allocate memory. */
106
+ return ;
203
107
}
108
+ }
204
109
205
- ring_buf_put_finish ( history -> ring_buf , 0 ) ;
206
- remove_from_tail ( history );
207
- } while ( 1 );
110
+ new -> len = len ;
111
+ memcpy ( new -> data , line , len );
112
+ sys_dlist_prepend ( & history -> list , & new -> dnode );
208
113
}
209
114
210
115
void z_shell_history_init (struct shell_history * history )
0 commit comments