How to check atomic records?

I searched hard (both on the S [O | F | U] network and elsewhere) and I think this is an unusual question. I work with the Atmel AT91SAM9263-EK development board (ARM926EJ-S kernel, ARMv5 instruction set) running Debian Linux 2.6.28-4. I am writing using (I believe) the tty driver to talk to the RS-485 serial controller . I need records and readings to be atomic. Several lines of source code (listed below the end of this message regarding the installation directory of the kernel source code) imply or implicitly define this.

Is there any way to verify that writing / reading to / from this device is actually an atomic operation? Or, is the device / dev / ttyXX considered FIFO, and the argument ends there? It seems that it is not enough just to trust that the code fulfills this claim, which it makes - as far back as February of this year, freebsd demonstrated the absence of atomic records for small lines . Yes, I understand that freebsd is not exactly the same as Linux, but I want to say that it does not hurt to be careful. All I can think of is to continue sending data and looking for a permutation - I was hoping for something more scientific and, ideally, deterministic. Unfortunately, I don’t remember anything exactly from my parallel programming classes in college days. I would appreciate a slap in the face or a push in the right direction. Thank you in advance if you decide to answer.

Yours faithfully,

Jayce


driver / char / tty_io.c: 1087

void tty_write_message(struct tty_struct *tty, char *msg) { lock_kernel(); if (tty) { mutex_lock(&tty->atomic_write_lock); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) tty->ops->write(tty, msg, strlen(msg)); tty_write_unlock(tty); } unlock_kernel(); return; } 


arc / arm / enable / ASM / bitops.h: 37

 static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p) { unsigned long flags; unsigned long mask = 1UL << (bit & 31); p += bit >> 5; raw_local_irq_save(flags); *p |= mask; raw_local_irq_restore(flags); } 


Drivers / serial / serial_core.c: 2376

 static int uart_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct uart_state *state = tty->driver_data; struct uart_port *port; struct circ_buf *circ; unsigned long flags; int c, ret = 0; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ if (!state || !state->info) { WARN_ON(1); return -EL3HLT; } port = state->port; circ = &state->info->xmit; if (!circ->buf) return 0; spin_lock_irqsave(&port->lock, flags); while (1) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) c = count; if (c <= 0) break; memcpy(circ->buf + circ->head, buf, c); circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); buf += c; count -= c; ret += c; } spin_unlock_irqrestore(&port->lock, flags); uart_start(tty); return ret; } 

In addition, write (3) documentation from a person:

An attempt to write to a pipe or FIFO has several key characteristics:

  • Atomic / non-atomic: A record is atomic if the entire amount recorded in one operation does not alternate with data from any other process. This is useful when multiple authors send data to a single reader. Applications should know how large a write request can be expected atomically. This maximum is called {PIPE_BUF}. This volume of IEEE Std 1003.1-2001 does not indicate whether write requests for more than {PIPE_BUF} bytes are atomic, but requires that records from {PIPE_BUF} or fewer bytes are atomic.
+4
source share
2 answers

I think that technically the devices are not FIFOs, so it is completely unclear which guarantees you are quoting should apply.

Are you worried about partial writing and reading in the process, or are you really reading and / or writing the same device from different processes? Assuming the latter, you might be better off implementing some kind of proxy process. The proxy owns the device exclusively and performs all reads and writes, thereby completely eliminating the problem of multipoint atomism.

In short, I advise you not to try to verify that "reading / writing from this device is actually an atomic operation." This will be difficult to do with confidence and leave you with an application that is prone to subtle crashes if a later version of Linux (or o / s in general) fails to implement atomicity the way you need it.

+3
source

I think PIPE_BUF is the right thing. Now records from less than PIPE_BUF bytes may not be atomic, but if they are not an OS error. I suppose you could ask here if the OS has known errors. But in fact, if he has a mistake, you just need to fix it immediately.

If you want to write more than PIPE_BUF atomically, I think you're out of luck. I don’t think that there is any way besides coordination and cooperation of applications to make sure that the records of large sizes occur atomically.

One solution to this problem is to install your own process in front of the device and make sure that everyone who wants to record the device binds this process and sends data to it. Then you can do whatever makes sense for your application in terms of atomicity guarantee.

+2
source

All Articles