2 * RelayFS locking scheme implementation.
4 * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
5 * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
7 * This file is released under the GPL.
10 #include <asm/relay.h>
11 #include "relay_locking.h"
15 * switch_buffers - switches between read and write buffers.
16 * @cur_time: current time.
17 * @cur_tsc: the TSC associated with current_time, if applicable
19 * @finalizing: if true, don't start a new buffer
20 * @resetting: if true,
22 * This should be called from with interrupts disabled.
25 switch_buffers(struct timeval cur_time,
30 int finalize_buffer_only)
35 if (!rchan->half_switch) {
36 bytes_written = rchan->callbacks->buffer_end(rchan->id,
37 cur_write_pos(rchan), write_buf_end(rchan),
38 cur_time, cur_tsc, using_tsc(rchan));
39 if (bytes_written == 0)
40 rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] =
41 write_buf_end(rchan) - cur_write_pos(rchan);
44 if (finalize_buffer_only) {
45 rchan->bufs_produced++;
49 chan_buf_end = rchan->buf + rchan->n_bufs * rchan->buf_size;
50 if((write_buf(rchan) + rchan->buf_size >= chan_buf_end) || resetting)
51 write_buf(rchan) = rchan->buf;
53 write_buf(rchan) += rchan->buf_size;
54 write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size;
55 write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve;
56 cur_write_pos(rchan) = write_buf(rchan);
58 rchan->buf_start_time = cur_time;
59 rchan->buf_start_tsc = cur_tsc;
67 if (!packet_delivery(rchan))
68 rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 0;
71 rchan->bufs_produced = rchan->bufs_produced + rchan->n_bufs;
72 rchan->bufs_produced -= rchan->bufs_produced % rchan->n_bufs;
73 rchan->bufs_consumed = rchan->bufs_produced;
74 rchan->bytes_consumed = 0;
75 update_readers_consumed(rchan, rchan->bufs_consumed, rchan->bytes_consumed);
76 } else if (!rchan->half_switch)
77 rchan->bufs_produced++;
79 rchan->half_switch = 0;
82 bytes_written = rchan->callbacks->buffer_start(rchan->id, cur_write_pos(rchan), rchan->buf_id, cur_time, cur_tsc, using_tsc(rchan));
83 cur_write_pos(rchan) += bytes_written;
88 * locking_reserve - reserve a slot in the buffer for an event.
90 * @slot_len: the length of the slot to reserve
91 * @ts: variable that will receive the time the slot was reserved
92 * @tsc: the timestamp counter associated with time
93 * @err: receives the result flags
94 * @interrupting: if this write is interrupting another, set to non-zero
96 * Returns pointer to the beginning of the reserved slot, NULL if error.
98 * The err value contains the result flags and is an ORed combination
101 * RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred
102 * RELAY_EVENT_DISCARD_NONE - event should not be discarded
103 * RELAY_BUFFER_SWITCH - buffer switch occurred
104 * RELAY_EVENT_DISCARD - event should be discarded (all buffers are full)
105 * RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer
108 locking_reserve(struct rchan *rchan,
118 *err = RELAY_BUFFER_SWITCH_NONE;
120 if (slot_len >= rchan->buf_size) {
121 *err = RELAY_WRITE_DISCARD | RELAY_WRITE_TOO_LONG;
125 if (rchan->initialized == 0) {
126 rchan->initialized = 1;
127 get_timestamp(&rchan->buf_start_time,
128 &rchan->buf_start_tsc, rchan);
129 rchan->unused_bytes[0] = 0;
130 bytes_written = rchan->callbacks->buffer_start(
131 rchan->id, cur_write_pos(rchan),
132 rchan->buf_id, rchan->buf_start_time,
133 rchan->buf_start_tsc, using_tsc(rchan));
134 cur_write_pos(rchan) += bytes_written;
135 *tsc = get_time_delta(ts, rchan);
136 return cur_write_pos(rchan);
139 *tsc = get_time_delta(ts, rchan);
141 if (in_progress_event_size(rchan)) {
142 interrupted_pos(rchan) = cur_write_pos(rchan);
143 cur_write_pos(rchan) = in_progress_event_pos(rchan)
144 + in_progress_event_size(rchan)
145 + interrupting_size(rchan);
148 in_progress_event_pos(rchan) = cur_write_pos(rchan);
149 in_progress_event_size(rchan) = slot_len;
150 interrupting_size(rchan) = 0;
153 if (cur_write_pos(rchan) + slot_len > write_limit(rchan)) {
154 if (atomic_read(&rchan->suspended) == 1) {
155 in_progress_event_pos(rchan) = NULL;
156 in_progress_event_size(rchan) = 0;
157 interrupting_size(rchan) = 0;
158 *err = RELAY_WRITE_DISCARD;
162 buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
163 if (buffers_ready == rchan->n_bufs - 1) {
164 if (!mode_continuous(rchan)) {
165 atomic_set(&rchan->suspended, 1);
166 in_progress_event_pos(rchan) = NULL;
167 in_progress_event_size(rchan) = 0;
168 interrupting_size(rchan) = 0;
169 get_timestamp(ts, tsc, rchan);
170 switch_buffers(*ts, *tsc, rchan, 0, 0, 1);
171 recalc_time_delta(ts, tsc, rchan);
172 rchan->half_switch = 1;
174 cur_write_pos(rchan) = write_buf_end(rchan) - 1;
175 *err = RELAY_BUFFER_SWITCH | RELAY_WRITE_DISCARD;
180 get_timestamp(ts, tsc, rchan);
181 switch_buffers(*ts, *tsc, rchan, 0, 0, 0);
182 recalc_time_delta(ts, tsc, rchan);
183 *err = RELAY_BUFFER_SWITCH;
186 return cur_write_pos(rchan);
190 * locking_commit - commit a reserved slot in the buffer
191 * @rchan: the channel
192 * @from: commit the length starting here
193 * @len: length committed
194 * @deliver: length committed
195 * @interrupting: not used
197 * Commits len bytes and calls deliver callback if applicable.
200 locking_commit(struct rchan *rchan,
206 cur_write_pos(rchan) += len;
209 cur_write_pos(rchan) = interrupted_pos(rchan);
210 interrupting_size(rchan) += len;
212 in_progress_event_size(rchan) = 0;
213 if (interrupting_size(rchan)) {
214 cur_write_pos(rchan) += interrupting_size(rchan);
215 interrupting_size(rchan) = 0;
220 if (bulk_delivery(rchan)) {
221 u32 cur_idx = cur_write_pos(rchan) - rchan->buf;
222 u32 cur_bufno = cur_idx / rchan->buf_size;
223 from = rchan->buf + cur_bufno * rchan->buf_size;
224 len = cur_idx - cur_bufno * rchan->buf_size;
226 rchan->callbacks->deliver(rchan->id, from, len);
232 * locking_finalize: - finalize last buffer at end of channel use
233 * @rchan: the channel
236 locking_finalize(struct rchan *rchan)
238 unsigned long int flags;
242 local_irq_save(flags);
243 get_timestamp(&time, &tsc, rchan);
244 switch_buffers(time, tsc, rchan, 1, 0, 0);
245 local_irq_restore(flags);
249 * locking_get_offset - get current and max 'file' offsets for VFS
250 * @rchan: the channel
251 * @max_offset: maximum channel offset
253 * Returns the current and maximum buffer offsets in VFS terms.
256 locking_get_offset(struct rchan *rchan,
260 *max_offset = rchan->buf_size * rchan->n_bufs - 1;
262 return cur_write_pos(rchan) - rchan->buf;
266 * locking_reset - reset the channel
267 * @rchan: the channel
268 * @init: 1 if this is a first-time channel initialization
270 void locking_reset(struct rchan *rchan, int init)
273 channel_lock(rchan) = SPIN_LOCK_UNLOCKED;
274 write_buf(rchan) = rchan->buf;
275 write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size;
276 cur_write_pos(rchan) = write_buf(rchan);
277 write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve;
278 in_progress_event_pos(rchan) = NULL;
279 in_progress_event_size(rchan) = 0;
280 interrupted_pos(rchan) = NULL;
281 interrupting_size(rchan) = 0;
285 * locking_reset_index - atomically set channel index to the beginning
286 * @rchan: the channel
288 * If this fails, it means that something else just logged something
289 * and therefore we probably no longer want to do this. It's up to the
292 * Returns 0 if the index was successfully set, negative otherwise
295 locking_reset_index(struct rchan *rchan, u32 old_idx)
302 relay_lock_channel(rchan, flags);
303 cur_idx = locking_get_offset(rchan, NULL);
304 if (cur_idx != old_idx) {
305 relay_unlock_channel(rchan, flags);
309 get_timestamp(&time, &tsc, rchan);
310 switch_buffers(time, tsc, rchan, 0, 1, 0);
312 relay_unlock_channel(rchan, flags);