On 19/06/2026 20:58, Dan Cross wrote:
In article <1113s0b$3f4nm$1@dont-email.me>, Bart <bc@freeuk.com> wrote:
On 19/06/2026 17:31, Dan Cross wrote:
[snip]
Why letters and not descriptive volume names?
These are letters that are physical labels next to each socket.
Not on my system.
This was hypothetical. That is, if USB sockets were labeled like my HDMI >example and those letters or numbers appeared also on menus.
If I
give instructions to somebody to use physical socket 'A', they can do
that even if the machine is powered off.
Huh. Kinda hard to access the files on the "A:" drive when the
system is powered off.
This is about plugging in the device, like I can plug in my PCV to HDMI1 >when the TV is still turned off.
I would find it frustrating to type
commands to a machine that isn't even running.
If I look at the back of my TV, I have HDMI sockets marked 1, 2, 3. TheSo the Unix scheme assigns each floppy drive a number. The only
same numbering appears on the on-screen A/V menu. It's simple and it works. >>
substantive difference is that with Unix, you `mount` the
filesystem on the removable drive onto some directory, making
the files on that floppy appear as part of the global file
namespace.
Content- or device-related labels can be shown too interrogated from
whatever is plugged-in and active (that is, on-screen), but that is
secondary.
Of course, when there are no dedicated cables and it is all wireless,
then it gets harder and not so simple.
None of this has to do with `fopen`.
Yet it hasn't stopped you having your say about a topic before declaring
it as off-topic.
On 6/18/2026 4:03 PM, Lawrence D?Oliveiro wrote:
If saving the overhead of one system call is so significant,
perhaps you shouldn?t be using that OS for high-performance network
operations ...
Humm... I think you are missing the point? ConnectEx/AcceptEx has
the option to send/recv data. That's it.
When you use ConnectEx or AcceptEx to send or receive data
immediately with the connection establishment, you aren't just
"shaving off a system call"; you are minimizing the idle time of the
IOCP...
On 6/19/2026 1:59 AM, Lawrence D?Oliveiro wrote:
I guess one can distinguish here what belongs in the VFS and shell, vs
On Fri, 19 Jun 2026 01:20:14 -0500, BGB wrote:
Maybe, but you wouldn't need "file://" for "fopen()" or similar,
since it is sort of an implied default in this case.
For an OS-level call, yes. But there are lots of higher-level toolkits
(particularly GUI-associated ones) that hook in a virtual-I/O layer
that allows accessing remote URLs as easily as opening local files.
what belongs in a file-browser or web browser.
As of yet, no file browser or web-browser, still basically at the level
of a very rudimentary GUI that has a shell window that can be used for
other programs.
What, no event loop?
A lot of normal programs use polling loops, but from the way
object-method dispatch works, it would not use a polling/loop or
event loop.
How would you distinguish between two floppy drives on a Unix-like
file system?
On 19/06/2026 08:20, BGB wrote:
On 6/18/2026 6:06 PM, Lawrence D?Oliveiro wrote:
On Thu, 18 Jun 2026 03:49:55 -0500, BGB wrote:
Just that it is also not a huge leap from:
ÿÿÿ tcp://whatever
ÿÿÿ udp://whatever
ÿÿÿ http://whatever
ÿÿÿ ftp://whatever
ÿÿÿ ...
To:
ÿÿÿ c:/whatever...
Yes it is.
In the former, that part before the colon is a protocol. In the
latter, it is now down to just indicating a filesystem drive. And not
even in a unique fashion, like with a volume UUID or something, but
with an arbitarily-assigned ?drive letter? which cannot be guaranteed
to be unique or persistent.
Well, on older Windows.
On newer systems, the OS remembers and will assign the same drives to
the same letter on each boot.
I am not sure what you call "newer", but IIRC Windows has done that
since Windows 3.1.ÿ The only letters you could assign yourself were for network drives, and they were persistent if you choose "persistent=yes".
Later versions of Windows (maybe NT4 or W2K?ÿ I can't remember the
details) let you choose the letter to use for other drives, such as additional harddrives, CD-ROMs and later still, USB drives.ÿ Those
choices were persistent.
Automatically chosen drive letters were, of course, inconsistent.ÿ And
when you have a lot of drives and network shares, they run out.
But, yeah, probably wouldn't do it the Windows way. Either they could
be specified as mounts (in mtab or such), or possibly treated as
aliases, say:
ÿÿ c:/ aliases to /mnt/c
Drive letters make sense when users wanted to distinguish between their
3.5" floppy "A:" and their 5.25" floppy "B:".ÿ They were still usable
when you had a hard drive with one partition.ÿ Once it was realistic to
have two drives in the one PC, and more than one partition on a disk,
they were outdated and too restrictive for comfort.
They were a product of their time, but offer nothing going forward.
Copying the concept in any way for a new system is a daft idea.
Though, granted, not much particular reason to do this...
Remember, we already have
ÿÿÿÿ file://whatever
for denoting files on the local filesystem. That allows the ?whatever?
part to span the entire filesystem, not just one volume/drive.
Maybe, but you wouldn't need "file://" for "fopen()" or similar, since
it is sort of an implied default in this case.
Then again, going into the weeds on this:
Would, say:
ÿÿ cd ftp://foo.org/pub/
ÿÿ ls
Even really make sense?...
That could be nice, at least for things that support a file and
directory model.ÿ It all depends on how you want to treat user
convenience, security, reliability, etc.
Or, would it be better to ask people to at least mount it into the VFS
or similar?...
You are likely to need a user name and password here somewhere.
Well, or other mysteries, like, say:
Should usermode applications be allowed to export COM-like interfaces
that could then be mounted into the VFS?...
Say, for example, an application exports an IFileSystem or IMount
interface to the VFS, and then one can issue a "mount" on it. Would
need some way for the VFS do deal gracefully if the application
becomes unresponsive or crashes though (preferably without nuking the
whole OS in the process).
Like "fuse" on Linux (and similar things on other systems) ?ÿ Usermode
is the way to go for anything that is not speed critical.
Vs, say, assuming programs that export interfaces (as services) to be
at least semi trsusted / stable...
On Fri, 19 Jun 2026 13:42:56 -0700, Chris M. Thomasson wrote:
On 6/18/2026 4:03 PM, Lawrence D?Oliveiro wrote:
If saving the overhead of one system call is so significant,
perhaps you shouldn?t be using that OS for high-performance network
operations ...
Humm... I think you are missing the point? ConnectEx/AcceptEx has
the option to send/recv data. That's it.
That ?that?s it? is precisely the point.
When you use ConnectEx or AcceptEx to send or receive data
immediately with the connection establishment, you aren't just
"shaving off a system call"; you are minimizing the idle time of the
IOCP...
If the userspace has to worry about keeping the kernel network stack
busy to that extent, then that?s another point in favour of the
simpler Linux way of doing things.
On Wed, 10 Jun 2026 00:24:35 -0700, Chris M. Thomasson wrote:
Windows I/O is unified and async across all device types ? that?s
the whole point of IOCP.
Sure. That same sort of feature was integral both the previous OSes
Dave Cutler had a hand in: VAX/VMS and RSX-11.
If anything, Unix is the one still trying to catch up with a real
async model (see: io_uring).
You mean Linux? Yes, it did inherit the Unix idea of ?all I/O is
blocking?, so to do non-blocking calls you should spawn extra
processes -- or from the 1990s onwards, extra threads.
I agree, it might be nice to see a complete separation within the
kernel between I/O operation management and process scheduling.
But, let?s face it, even with the current model, Linux server
performance still leaves Windows for dead.
Well, actually, a lot of people don't know how to use IOCP
efficiently. They also don't know how to program an efficient server
logic. On Linux, use io_uring. On Windows use IOCP.
I am talking about highly scalable servers under heavy load.
What is the analog of ConnectEx/AcceptEx on Linux?
On Fri, 19 Jun 2026 16:47:35 -0700, Chris M. Thomasson wrote:
Well, actually, a lot of people don't know how to use IOCP
efficiently. They also don't know how to program an efficient server
logic. On Linux, use io_uring. On Windows use IOCP.
If IOCP is the only way to achieve decent server performance on
Windows, no surprise that people find the *nix programming model
simpler.
And this is without even resorting to io_uring.
On Fri, 19 Jun 2026 16:40:07 -0700, Chris M. Thomasson wrote:
I am talking about highly scalable servers under heavy load.
So am I.
What is the analog of ConnectEx/AcceptEx on Linux?
Doesn?t need one. It can whip Windows? arse quite nicely without it.
So, what's it like under Linux: if I plug a pen drive into my RPi,
then the files will be at:
/media/bart/EEBEBEBEC313CA9B
Obviously.
If I try another, then it's at /media/bart/NEW (note these are case-sensitive) ...
But I've used a couple of DEC OSes and don't remember drive letters.
Google AI tells me: "Drive letters originate from the CP/M operating
system in the 1970s and were popularized by MS-DOS."
And this is without even resorting to io_uring.
io_uring is the way to go on Linux for high performance servers.
Actually, its more complicated than IOCP.
On 6/19/2026 7:50 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:40:07 -0700, Chris M. Thomasson wrote:
I am talking about highly scalable servers under heavy load.
So am I.
What is the analog of ConnectEx/AcceptEx on Linux?
Doesn?t need one. It can whip Windows? arse quite nicely without it.
But it seems to have one? io_uring_enter... IORING_OP_ACCEPT and IORING_OP_CONNECT ?
Bart <bc@freeuk.com> writes:
On 19/06/2026 18:33, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
[...]
How would you distinguish between two floppy drives on a Unix-like
file system?
If writing a common shell script for other people to use on their own
machines, would you be able to use the same designations?
I'd ask in a forum that discusses Unix-like systems, not one that
discusses the C programming language.
Here's the thing: this is thread that has been wildly off-topic for
nearly 100 posts, even aside from the other off-topic threads.
Yet you pick on MY post and tell only ME to move the discussion elsewhere.
perhaps it is because _you_ are most often the poster who
moves the thread off-topic?
On Fri, 19 Jun 2026 14:47:31 -0500, BGB wrote:
On 6/19/2026 1:59 AM, Lawrence D?Oliveiro wrote:
I guess one can distinguish here what belongs in the VFS and shell, vs
On Fri, 19 Jun 2026 01:20:14 -0500, BGB wrote:
Maybe, but you wouldn't need "file://" for "fopen()" or similar,
since it is sort of an implied default in this case.
For an OS-level call, yes. But there are lots of higher-level toolkits
(particularly GUI-associated ones) that hook in a virtual-I/O layer
that allows accessing remote URLs as easily as opening local files.
what belongs in a file-browser or web browser.
I should mention that Linux has a filesystem plugin API called FUSE,
which allows filesystem implementations to be done in userland. Not everything has to be a kernel module.
Example: secure remote access to filesystems on other machines via SSH <https://github.com/libfuse/sshfs>.
On 6/19/2026 7:49 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:47:35 -0700, Chris M. Thomasson wrote:
io_uring is the way to go on Linux for high performance servers.
Actually, its more complicated than IOCP.
Compared to Windows machines with its pseudorandom system for
assigning COM port numbers,
On 19/06/2026 18:33, Keith Thompson wrote:
Bart <bc@freeuk.com> writes:
[...]
How would you distinguish between two floppy drives on a Unix-like
file system?
If writing a common shell script for other people to use on their own
machines, would you be able to use the same designations?
I'd ask in a forum that discusses Unix-like systems, not one that
discusses the C programming language.
Here's the thing: this is thread that has been wildly off-topic for
nearly 100 posts, even aside from the other off-topic threads.
Yet you pick on MY post and tell only ME to move the discussion elsewhere.
On Fri, 19 Jun 2026 17:25:01 +0200
David Brown <david.brown@hesbynett.no> wrote:
Compared to Windows machines with its pseudorandom system for
assigning COM port numbers,
There is a system in the madness. Behavior depends on either your USB-to-serial device has USB serial Id or lacks it.
If it has Id then the same port will be assigned to the same device regardless of the USB port that device plugged in this time.
Otherwise port number is assigned per USB port. Mostly.
Cheap FTDI clones tend to not implement serial ID.
Silicon Lab based converters tends to be of better quality, not just relatively to clones, but also relatively to genuine FTDI controllers.
On 21/06/2026 00:42, Michael S wrote:
On Fri, 19 Jun 2026 17:25:01 +0200
David Brown <david.brown@hesbynett.no> wrote:
Compared to Windows machines with its pseudorandom system for
assigning COM port numbers,
There is a system in the madness. Behavior depends on either your USB-to-serial device has USB serial Id or lacks it.
If it has Id then the same port will be assigned to the same device regardless of the USB port that device plugged in this time.
Otherwise port number is assigned per USB port. Mostly.
It is the "mostly" that is the killer.
The port numbers are usually stable if you plug the same devices into
the same physical ports. But sometimes if you have had a number of
new devices attached in the meantime, then go back to the old ones,
Windows might forget the previous numbers, or even re-use them, and
your old devices get new numbers. Mixing devices from different manufacturers appears to make things worse, but I have not done
extensive trials.
If you just have a few devices that you use regularly, it's okay - so
for most of our developers the port numbers don't get too high within
the lifetime of a useable Windows system. For some test machines
it's a different matter - when you build boards with a USB-to-serial
chip onboard, if those chips have serial numbers then you chew
through COM port numbers at an alarming rate. It is just one of many
reasons why we usually try to use Linux (especially Pi's) for test
machines.
Cheap FTDI clones tend to not implement serial ID.
Silicon Lab based converters tends to be of better quality, not just relatively to clones, but also relatively to genuine FTDI
controllers.
I don't remember ever using an FTDI clone - FTDI devices and cables
are not expensive enough for it to make sense for us. And FTDI
devices have worked fine for our needs. I have used a few Silicon
Labs devices too, but I don't see anything to suggest they are
"better quality" - pretty much every USB-to-serial converter from
every manufacturer works fine and does its job.
Some do cause more
pain with Windows then others, with different drivers and
requirements, but that's Windows and/or driver problems, and usually
those problems are surmountable. In the end, it is usually up to the customer - if they want a USB-to-serial converter on their board, and
they've picked a type, that's what they get. Given a free choice, we generally go for FTDI ourselves. (Most common is that boards have a
simple header with TTL signals and we use an external FTDI cable -
the biggest use of serial ports between boards and PC's is for
debugging and testing.)
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/19/2026 7:49 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:47:35 -0700, Chris M. Thomasson wrote:
io_uring is the way to go on Linux for high performance servers.
Actually, its more complicated than IOCP.
The posix asynchronous I/O facilities (e.g lio_listio(2)) were
used in the Oracle ODM (Operating System Dependent module)
of the RDMS product for high performance unix implementations
with lots of spindles more than a quarter century ago.
On Fri, 19 Jun 2026 19:53:15 -0700, Chris M. Thomasson wrote:
On 6/19/2026 7:50 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:40:07 -0700, Chris M. Thomasson wrote:
I am talking about highly scalable servers under heavy load.
So am I.
What is the analog of ConnectEx/AcceptEx on Linux?
Doesn?t need one. It can whip Windows? arse quite nicely without it.
But it seems to have one? io_uring_enter... IORING_OP_ACCEPT and
IORING_OP_CONNECT ?
I can?t find anything that uses it.
On 6/19/2026 8:59 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 19:53:15 -0700, Chris M. Thomasson wrote:
On 6/19/2026 7:50 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:40:07 -0700, Chris M. Thomasson wrote:
I am talking about highly scalable servers under heavy load.
So am I.
What is the analog of ConnectEx/AcceptEx on Linux?
Doesn?t need one. It can whip Windows? arse quite nicely without
it.
But it seems to have one? io_uring_enter... IORING_OP_ACCEPT and
IORING_OP_CONNECT ?
I can?t find anything that uses it.
So what does that mean? They are there, right?
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
On 21/06/2026 00:42, Michael S wrote:
On Fri, 19 Jun 2026 17:25:01 +0200
David Brown <david.brown@hesbynett.no> wrote:
Compared to Windows machines with its pseudorandom system for
assigning COM port numbers,
There is a system in the madness. Behavior depends on either your
USB-to-serial device has USB serial Id or lacks it.
If it has Id then the same port will be assigned to the same device
regardless of the USB port that device plugged in this time.
Otherwise port number is assigned per USB port. Mostly.
It is the "mostly" that is the killer.
The port numbers are usually stable if you plug the same devices into
the same physical ports. But sometimes if you have had a number of
new devices attached in the meantime, then go back to the old ones,
Windows might forget the previous numbers, or even re-use them, and
your old devices get new numbers. Mixing devices from different
manufacturers appears to make things worse, but I have not done
extensive trials.
If you just have a few devices that you use regularly, it's okay - so
for most of our developers the port numbers don't get too high within
the lifetime of a useable Windows system. For some test machines
it's a different matter - when you build boards with a USB-to-serial
chip onboard, if those chips have serial numbers then you chew
through COM port numbers at an alarming rate. It is just one of many
reasons why we usually try to use Linux (especially Pi's) for test
machines.
Serial device API of Linux (inherited from early Unixes) is too kludgy
to my liking. Why oh why do they think that serial port somehow has to
be related to terminal ?!
Windows API makes more sense.
The difference mattered in the past, when we had to implement
SCADA-style protocols on PC host. Fortunately, we do not doing it any
longer.
Cheap FTDI clones tend to not implement serial ID.
Silicon Lab based converters tends to be of better quality, not just
relatively to clones, but also relatively to genuine FTDI
controllers.
I don't remember ever using an FTDI clone - FTDI devices and cables
are not expensive enough for it to make sense for us. And FTDI
devices have worked fine for our needs. I have used a few Silicon
Labs devices too, but I don't see anything to suggest they are
"better quality" - pretty much every USB-to-serial converter from
every manufacturer works fine and does its job.
I wish it was true.
Unfortunately I had seen misdesigned hardware more than one time,
including hardware from major manufactorer, like Aten.
One case I can not forget is USB-1.1 device that claimed to support
912 Kbps, but had 64-byte recieve and transmit queues. Of course, USB
polling rate is 1KHz, so it can't work even in theory, much less in
practice.
Some do cause more
pain with Windows then others, with different drivers and
requirements, but that's Windows and/or driver problems, and usually
those problems are surmountable. In the end, it is usually up to the
customer - if they want a USB-to-serial converter on their board, and
they've picked a type, that's what they get. Given a free choice, we
generally go for FTDI ourselves. (Most common is that boards have a
simple header with TTL signals and we use an external FTDI cable -
the biggest use of serial ports between boards and PC's is for
debugging and testing.)
As long as requirements are minimal, everything goes.
Try something just a little bit more demanding, like programming flash
on ST or TI microcontroller by means of vendor-supplied utility, and
many USB-to-serial converters will cause you problems.
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too kludgy
to my liking. Why oh why do they think that serial port somehow has to
be related to terminal ?!
On 6/20/2026 8:49 AM, Scott Lurndal wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/19/2026 7:49 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:47:35 -0700, Chris M. Thomasson wrote:
io_uring is the way to go on Linux for high performance servers.
Actually, its more complicated than IOCP.
The posix asynchronous I/O facilities (e.g lio_listio(2)) were
used in the Oracle ODM (Operating System Dependent module)
of the RDMS product for high performance unix implementations
with lots of spindles more than a quarter century ago.
Afaict, io_uring is the way to go on Linux. Or want to go POSIX? AIO.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/20/2026 8:49 AM, Scott Lurndal wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
On 6/19/2026 7:49 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:47:35 -0700, Chris M. Thomasson wrote:
io_uring is the way to go on Linux for high performance servers.
Actually, its more complicated than IOCP.
The posix asynchronous I/O facilities (e.g lio_listio(2)) were
used in the Oracle ODM (Operating System Dependent module)
of the RDMS product for high performance unix implementations
with lots of spindles more than a quarter century ago.
Afaict, io_uring is the way to go on Linux. Or want to go POSIX? AIO.
That's what I said. lio_listio(2) is one of the several POSIX
asynchronous I/O interfaces.
On Wed, 10 Jun 2026 12:37:47 +0200, fir wrote:
why you think YOU SHOULD be waiting? waiting makes some
complications (like for example you can wait only on one thing ...
Heck, no. Look at this man page <https://manpages.debian.org/poll(2)>:
you give it a collection of FDs (these can be any mixture of things
like sockets, pipes, character devices ... actually any kind of file
is valid). You specify for each one whether you are waiting for it to
be read-ready, write-ready, or both. And on top of that you can
specify a timeout, in case you have some other tasks to perform that
you don?t want to hold up for *too* long.
A common use for the timeout is to do a periodic scan for client
network connections that have gone idle for too long, so the server
should give up and abandon those connections.
And then the call returns when one or more of those FDs are in the
specified states, or the timeout (if specified) has elapsed.
An even more advanced set of calls is this <https://manpages.debian.org/epoll(7)>. That offers the option for
monitoring individual FDs on a level-triggered or edge-triggered
basis.
On Sun, 21 Jun 2026 16:31:03 -0700, Chris M. Thomasson wrote:
On 6/19/2026 8:59 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 19:53:15 -0700, Chris M. Thomasson wrote:
On 6/19/2026 7:50 PM, Lawrence D?Oliveiro wrote:
On Fri, 19 Jun 2026 16:40:07 -0700, Chris M. Thomasson wrote:
I am talking about highly scalable servers under heavy load.
So am I.
What is the analog of ConnectEx/AcceptEx on Linux?
Doesn?t need one. It can whip Windows? arse quite nicely without
it.
But it seems to have one? io_uring_enter... IORING_OP_ACCEPT and
IORING_OP_CONNECT ?
I can?t find anything that uses it.
So what does that mean? They are there, right?
It just reinforces my point, that Linux servers, particularly network-intensive ones, can run rings around their Windows competitors without needing to resort to such extreme-performance tricks.
Fwiw, remember that DisconnectEx call in Windows with the
TF_REUSE_SOCKET flag? Pretty nice:
https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_disconnectex
On 6/21/2026 5:59 PM, Lawrence D?Oliveiro wrote:
It just reinforces my point, that Linux servers, particularly
network-intensive ones, can run rings around their Windows
competitors without needing to resort to such extreme-performance
tricks.
So, why did they even create io_uring?
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too kludgy
to my liking. Why oh why do they think that serial port somehow has to
be related to terminal ?!
Can you elaborate on that? What do you mean 'related to a terminal'?
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions (tcsetattr/tcgetattr)
and using standard filesystem calls for reading and writing.
Once the serial port is opened, it is a simple byte stream just like
any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too kludgy
to my liking. Why oh why do they think that serial port somehow has to
be related to terminal ?!
Can you elaborate on that? What do you mean 'related to a terminal'?
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions (tcsetattr/tcgetattr)
and using standard filesystem calls for reading and writing.
Once the serial port is opened, it is a simple byte stream just like
any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation: ><https://docs.kernel.org/driver-api/serial/driver.html>
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a
total mess - it's all for handling serial terminals from the 1970's.
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too kludgy >>>> to my liking. Why oh why do they think that serial port somehow has to >>>> be related to terminal ?!
Can you elaborate on that? What do you mean 'related to a terminal'?
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions (tcsetattr/tcgetattr)
and using standard filesystem calls for reading and writing.
Once the serial port is opened, it is a simple byte stream just like
any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation:
<https://docs.kernel.org/driver-api/serial/driver.html>
Which describes how to write a kernel driver for a new
serial port (of which there hasn't been new hardware since
the PL011). Certainly not of interest or use to the average
user.
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
It's a
total mess - it's all for handling serial terminals from the 1970's.
I'm sure that the microprocessors you routinely use all still
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
On 23/06/2026 17:35, Scott Lurndal wrote:
It's a
total mess - it's all for handling serial terminals from the 1970's.
I'm sure that the microprocessors you routinely use all still
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have
UARTs that have register sets compatible with them, but I don't think it
is common. Microcontrollers certainly don't make any attempt to have >compatibility with those register sets.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF,
or hardware flow control (the RTS signal is often used for RS-485 drive >enable), and regularly use 3 MBaud for local connections to fast >microcontrollers.
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud >rate, possibly enabling the RTS line as an RS-485 driver enable, picking >8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
can be useful for UARTs, such as getting feedback when everything is
sent (via a semaphore, condition variable, or similar synchronisation >mechanism),
getting feedback when there has been a pause since the last
received character, and other such things. AFAIK these are not
available with standard Linux serial port handling.
In article <111eavb$2c615$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 17:35, Scott Lurndal wrote:
It's a
total mess - it's all for handling serial terminals from the 1970's.
I'm sure that the microprocessors you routinely use all still
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have
UARTs that have register sets compatible with them, but I don't think it
is common. Microcontrollers certainly don't make any attempt to have
compatibility with those register sets.
This is simply incorrect. Lots of parts still have integrated 16550-compatible UARTs; the designware part that is common in a
lot of SoC's will even go up to 3MBAUD.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF,
or hardware flow control (the RTS signal is often used for RS-485 drive
enable), and regularly use 3 MBaud for local connections to fast
microcontrollers.
I use 3MBAUD, 16550-compatible UARTs embedded in AMD's EPYC SoCs
daily. We use hardware flow control to avoid dropping
characters when speaking to a fast uctlr running our own
embedded OS. The DW part in the SoC even supports auto HW flow
control and manages the FIFOs and signaling more or less
independently of the host (which actually caused a problem in
our driver a few months back).
If reliable delivery of data is important to you, some kind of
flow control is useful, whether hardware or software based. If
it's just for debug spew, you may not care.
David Brown <david.brown@hesbynett.no> writes:
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud
rate, possibly enabling the RTS line as an RS-485 driver enable, picking
8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
I would separate those into two distinct operations:
- One-time setup. Setting the line characteristics (baud rate,
stop-bits, parity) and the UART characteristics (flow
control, Rx and Tx FIFOs, Carrier Detect). For which there
are standard POSIX interfaces (tcsetattr/tcgetattr)
- steady-state operations, such as reading and writing which
use the normal file I/O operations (read, write, poll, et alia)
There are other possible features that
can be useful for UARTs, such as getting feedback when everything is
sent (via a semaphore, condition variable, or similar synchronisation
mechanism),
That really depends on OS API. STDIO buffers output, and provides
a mechanism to flush the buffers. If one bypasses stdio and uses
read/write, the programmer can call tcdrain() to ensure the data
has been transmitted or set VMIN=1 and VTIME=0 with tcsetattr
to avoid any buffering in the kernel driver.
getting feedback when there has been a pause since the last
received character, and other such things. AFAIK these are not
available with standard Linux serial port handling.
The poll(2) system call can be used for this purpose, as it
can timeout if there is no character received within a
specified interval.
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too
kludgy to my liking. Why oh why do they think that serial port
somehow has to be related to terminal ?!
Can you elaborate on that? What do you mean 'related to a
terminal'?
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just
like any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation: ><https://docs.kernel.org/driver-api/serial/driver.html>
Which describes how to write a kernel driver for a new
serial port (of which there hasn't been new hardware since
the PL011). Certainly not of interest or use to the average
user.
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
It's a
total mess - it's all for handling serial terminals from the 1970's.
I'm sure that the microprocessors you routinely use all still
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
Serial device API of Linux (inherited from early Unixes) is too
kludgy to my liking. Why oh why do they think that serial port
somehow has to be related to terminal ?!
Can you elaborate on that? What do you mean 'related to a
terminal'?
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just like
any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation: <https://docs.kernel.org/driver-api/serial/driver.html> or <https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a total mess - it's all for handling serial terminals from the
1970's. Most of it is, of course, just a one-off setting - once you
have got the termio stuff right,
and haven't accidentally got some
extra character translation or flow control, then it's just simple
reads and writes.
Of course it is hard to remove stuff once it is there - user space
APIs are, rightly, as stable as they possibly can be.
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated
16x50 UART chip, possibly a 16450.)
On Mon, 22 Jun 2026 13:42:20 -0700, Chris M. Thomasson wrote:
Fwiw, remember that DisconnectEx call in Windows with the
TF_REUSE_SOCKET flag? Pretty nice:
https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_disconnectex
My word:
?Note
The function pointer for the DisconnectEx function must be
obtained at run time by making a call to the WSAIoctl function
with the SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. The
input buffer passed to the WSAIoctl function must contain
WSAID_DISCONNECTEX, a globally unique identifier (GUID) whose
value identifies the DisconnectEx extension function. On success,
the output returned by the WSAIoctl function contains a pointer to
the DisconnectEx function. The WSAID_DISCONNECTEX GUID is defined
in the Mswsock.h header file.
What the heck is that all about?
This <https://manpages.debian.org/setsockopt(2)> is so much simpler
...
On Mon, 22 Jun 2026 14:06:58 -0700, Chris M. Thomasson wrote:
On 6/21/2026 5:59 PM, Lawrence D?Oliveiro wrote:
It just reinforces my point, that Linux servers, particularly
network-intensive ones, can run rings around their Windows
competitors without needing to resort to such extreme-performance
tricks.
So, why did they even create io_uring?
Obviously, it has its specialized uses, in rarefied realms beyond the imaginings of those only familiar with Dave-Cutler-type operating
systems ...
David Brown <david.brown@hesbynett.no> writes:
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud
rate, possibly enabling the RTS line as an RS-485 driver enable, picking
8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
I would separate those into two distinct operations:
- One-time setup. Setting the line characteristics (baud rate,
stop-bits, parity) and the UART characteristics (flow
control, Rx and Tx FIFOs, Carrier Detect). For which there
are standard POSIX interfaces (tcsetattr/tcgetattr)
- steady-state operations, such as reading and writing which
use the normal file I/O operations (read, write, poll, et alia)
There are other possible features that
can be useful for UARTs, such as getting feedback when everything is
sent (via a semaphore, condition variable, or similar synchronisation
mechanism),
That really depends on OS API. STDIO buffers output, and provides
a mechanism to flush the buffers. If one bypasses stdio and uses
read/write, the programmer can call tcdrain() to ensure the data
has been transmitted or set VMIN=1 and VTIME=0 with tcsetattr
to avoid any buffering in the kernel driver.
getting feedback when there has been a pause since the last
received character, and other such things. AFAIK these are not
available with standard Linux serial port handling.
The poll(2) system call can be used for this purpose, as it
can timeout if there is no character received within a
specified interval.
Basically to gain those extensions, we need something like. This is
HYPER crude so try not to spill your coffee while reading it. ;^D
rofl.
I think its a rather low level way to make high end servers/clients
akin to dx12/vulkan vs modern opengl?
On Tue, 23 Jun 2026 21:07:48 +0200
David Brown <david.brown@hesbynett.no> wrote:
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated
16x50 UART chip, possibly a 16450.)
I think, I had seen one, in the early 2000, on IBM PPC 4xx embedded
chip. Whether it should be considered MCU or embedded processor is a
matter of opinion. But it was pretty low end chip, esp. comparatively to PowerQUICC I that I was used to back in this era.
Other than that I agree. It seems that Dan Cross has no [1st-hand programming] experience with MCUs.
On 23/06/2026 19:12, Dan Cross wrote:
In article <111eavb$2c615$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 17:35, Scott Lurndal wrote:
It's a
total mess - it's all for handling serial terminals from the 1970's.
I'm sure that the microprocessors you routinely use all still
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have
UARTs that have register sets compatible with them, but I don't think it >>> is common. Microcontrollers certainly don't make any attempt to have
compatibility with those register sets.
This is simply incorrect. Lots of parts still have integrated
16550-compatible UARTs; the designware part that is common in a
lot of SoC's will even go up to 3MBAUD.
I don't know all embedded microprocessors. I suspect that in order to >remain as "PC compatible" as possible, x86 SoC's might have 16550
compatible UARTs.
Many others do not. The NXP i.mx family, which is one of the most
popular in industrial usage, have UARTs that do not have 16550 register >sets. There is a reason linux/drivers/tty/serial has several dozen C
files, supporting several dozen UARTs. Critically, embedded UARTs >(excluding 16550 compatible ones) support DMA.
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated 16x50
UART chip, possibly a 16450.)
Of course all these UARTs can /talk/ to 16550 UARTs,
but they are not
compatible in their design or hardware register maps despite plenty of >similarity.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF,
or hardware flow control (the RTS signal is often used for RS-485 drive
enable), and regularly use 3 MBaud for local connections to fast
microcontrollers.
I use 3MBAUD, 16550-compatible UARTs embedded in AMD's EPYC SoCs
daily. We use hardware flow control to avoid dropping
characters when speaking to a fast uctlr running our own
embedded OS. The DW part in the SoC even supports auto HW flow
control and manages the FIFOs and signaling more or less
independently of the host (which actually caused a problem in
our driver a few months back).
If reliable delivery of data is important to you, some kind of
flow control is useful, whether hardware or software based. If
it's just for debug spew, you may not care.
If your systems are fast enough, and you have the right priorities for
your threads, interrupts, DMAs, etc., then you don't need flow control.
And most protocols (other than debug outputs) used over serial ports in >embedded systems are not continuous traffic flows - you have packets,
and typically have request/response patterns. As long as you have DMA
to give you FIFOs that are big enough, you can consider the packet
reception and answering as high-level software flow control.
On Tue, 23 Jun 2026 21:07:48 +0200
David Brown <david.brown@hesbynett.no> wrote:
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated
16x50 UART chip, possibly a 16450.)
I think, I had seen one, in the early 2000, on IBM PPC 4xx embedded
chip. Whether it should be considered MCU or embedded processor is a
matter of opinion. But it was pretty low end chip, esp. comparatively to >PowerQUICC I that I was used to back in this era.
Other than that I agree. It seems that Dan Cross has no [1st-hand >programming] experience with MCUs.
On 23/06/2026 19:39, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud
rate, possibly enabling the RTS line as an RS-485 driver enable, picking >>> 8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
I would separate those into two distinct operations:
Yes.
- One-time setup. Setting the line characteristics (baud rate,
stop-bits, parity) and the UART characteristics (flow
control, Rx and Tx FIFOs, Carrier Detect). For which there
are standard POSIX interfaces (tcsetattr/tcgetattr)
- steady-state operations, such as reading and writing which
use the normal file I/O operations (read, write, poll, et alia)
Agreed.
It's only the setup that is a pain because of legacy terminal support.
There are other possible features that
can be useful for UARTs, such as getting feedback when everything is
sent (via a semaphore, condition variable, or similar synchronisation
mechanism),
That really depends on OS API. STDIO buffers output, and provides
a mechanism to flush the buffers. If one bypasses stdio and uses
read/write, the programmer can call tcdrain() to ensure the data
has been transmitted or set VMIN=1 and VTIME=0 with tcsetattr
to avoid any buffering in the kernel driver.
getting feedback when there has been a pause since the last
received character, and other such things. AFAIK these are not
available with standard Linux serial port handling.
The poll(2) system call can be used for this purpose, as it
can timeout if there is no character received within a
specified interval.
I guess I am used to microcontroller programming - things happen far
more directly and efficiently there. (Or I use Python, were the source
code is simple and easy, and you don't think about the layers in between
the code and the hardware!)
On Tue, 23 Jun 2026 14:41:28 -0700, Chris M. Thomasson wrote:
I think its a rather low level way to make high end servers/clients
akin to dx12/vulkan vs modern opengl?
No. Async I/O is all about performance. Whereas a programmable
shader pipeline is all about versatility.
On Tue, 23 Jun 2026 14:40:18 -0700, Chris M. Thomasson wrote:
Basically to gain those extensions, we need something like. This is
HYPER crude so try not to spill your coffee while reading it. ;^D
rofl.
Microsoft have no idea how to do shared-library versioning, do they?
On Tue, 23 Jun 2026 07:25:56 +0200
David Brown <david.brown@hesbynett.no> wrote:
[snip]
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud rate,
stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just like
any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation:
<https://docs.kernel.org/driver-api/serial/driver.html> or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a total mess - it's all for handling serial terminals from the
1970's. Most of it is, of course, just a one-off setting - once you
have got the termio stuff right,
Configuration API sometimes matters.
In particular, support for various timeouts in termio is subpar
relatively to what you have in Windows. May be, Windows has too many of
them, esp. on the transmit side, but termios certainly has too few.
What is even worse, is resolution. Out of memory, resolution of
timeouts in termios is 0.1 sec. For SCADA-style protocols that's
useless.
So, it seems, the only way to implement such protocols on Linux or
similar OSes, is to read one character at time by very high priority
thread. And to pray for good luck.
Today, with many cores available everiwhere, the chance for ending up
lucky is decent. 25 years ago - less so.
and haven't accidentally got some
extra character translation or flow control, then it's just simple
reads and writes.
Of course it is hard to remove stuff once it is there - user space
APIs are, rightly, as stable as they possibly can be.
But it is possible to add better API without removing old stuff.
May be, it even exists. I didn't follow the field since ~2021.
On 6/23/2026 7:05 PM, Lawrence D?Oliveiro wrote:
On Tue, 23 Jun 2026 14:41:28 -0700, Chris M. Thomasson wrote:
I think its a rather low level way to make high end servers/clients
akin to dx12/vulkan vs modern opengl?
No. Async I/O is all about performance. Whereas a programmable
shader pipeline is all about versatility.
But take a look on how to have to use io_uring? You have to mmap your
ring buffers and tell the kernel about them. Its more low-level, like
dx12 is more low level than modern opengl?
In article <111eli4$2g1qh$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 19:12, Dan Cross wrote:
In article <111eavb$2c615$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 17:35, Scott Lurndal wrote:
It's aI'm sure that the microprocessors you routinely use all still
total mess - it's all for handling serial terminals from the 1970's. >>>>>
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have
UARTs that have register sets compatible with them, but I don't think it >>>> is common. Microcontrollers certainly don't make any attempt to have
compatibility with those register sets.
This is simply incorrect. Lots of parts still have integrated
16550-compatible UARTs; the designware part that is common in a
lot of SoC's will even go up to 3MBAUD.
I don't know all embedded microprocessors. I suspect that in order to
remain as "PC compatible" as possible, x86 SoC's might have 16550
compatible UARTs.
Essentially every modern x86 SoC has at least one; usually
several. They may or may not be lined out, but they're there.
Some other systems may use 16550-compatible parts as well; as I
mentioned, DesignWare markets one as an embeddable piece of IP
that one can incorporate into one's own design.
Many others do not. The NXP i.mx family, which is one of the most
popular in industrial usage, have UARTs that do not have 16550 register
sets. There is a reason linux/drivers/tty/serial has several dozen C
files, supporting several dozen UARTs. Critically, embedded UARTs
(excluding 16550 compatible ones) support DMA.
I did not say that other systems used 16550, I was disputing the
incorrect statement that "16550 UARTs are long obsolete." If
you mean discrete UART chips signaling at TTL levels, whether
shifted to RS-232 levels or not, you're correct, but I took your
statement to be more general. Simply, they are not obsolete at
all, and they're extraordinarily common.
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated 16x50
UART chip, possibly a 16450.)
Ok, but your personal experience is anecdotal and by your own
admission not representative of large machines. Judging that
the obsolesence (or not) of a part based on your own experience
alone is not a great way to make judgements about these things.
Of course all these UARTs can /talk/ to 16550 UARTs,
Yes, that's the whole point of a serial protocol between
disparate systems. :-)
but they are not
compatible in their design or hardware register maps despite plenty of
similarity.
If you go back and re-read Scott's statement, he said modern
systems are usually using a 16550 or a PL101-compatible UART.
That's true; ARM and x86 parts are extraordinarily common.
Of course, there are and have been others; I've personally
worked with Zilog and Motorola parts in addition to the
aforementioned two.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF, >>>> or hardware flow control (the RTS signal is often used for RS-485 drive >>>> enable), and regularly use 3 MBaud for local connections to fast
microcontrollers.
I use 3MBAUD, 16550-compatible UARTs embedded in AMD's EPYC SoCs
daily. We use hardware flow control to avoid dropping
characters when speaking to a fast uctlr running our own
embedded OS. The DW part in the SoC even supports auto HW flow
control and manages the FIFOs and signaling more or less
independently of the host (which actually caused a problem in
our driver a few months back).
If reliable delivery of data is important to you, some kind of
flow control is useful, whether hardware or software based. If
it's just for debug spew, you may not care.
If your systems are fast enough, and you have the right priorities for
your threads, interrupts, DMAs, etc., then you don't need flow control.
And most protocols (other than debug outputs) used over serial ports in
embedded systems are not continuous traffic flows - you have packets,
and typically have request/response patterns. As long as you have DMA
to give you FIFOs that are big enough, you can consider the packet
reception and answering as high-level software flow control.
Again, extrapolating from your own personal experience to other
areas is leading to a specious conclusion. You hinted at the
issue: _if_ your systems can keep up, you may be ok. But on a
large system, running a multiuser multitasking operating system,
doing a ton of IO on high speed devices, dealing with many
thousands of interrupts a second across many cores, you may not
be able to keep up.
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 19:39, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud >>>> rate, possibly enabling the RTS line as an RS-485 driver enable, picking >>>> 8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
I would separate those into two distinct operations:
Yes.
- One-time setup. Setting the line characteristics (baud rate,
stop-bits, parity) and the UART characteristics (flow
control, Rx and Tx FIFOs, Carrier Detect). For which there
are standard POSIX interfaces (tcsetattr/tcgetattr)
- steady-state operations, such as reading and writing which
use the normal file I/O operations (read, write, poll, et alia)
Agreed.
It's only the setup that is a pain because of legacy terminal support.
Is it really that hard?
struct termios term;
memset(&term, 0, sizeof(term));
cfmakeraw(&term); // BSD extension
cfsetispeed(&term, B38400);
cfsetospeed(&term, B38400);
term.c_cflag |= CS8 | CREAD | CRTSCTS;
tcsetattr(fd, TCSANOW, &term)
Of course, on plan 9, it's even easier:
echo -n b38400 l8 pn s1 >/dev/eia1ctl
There are other possible features that
can be useful for UARTs, such as getting feedback when everything is
sent (via a semaphore, condition variable, or similar synchronisation
mechanism),
That really depends on OS API. STDIO buffers output, and provides
a mechanism to flush the buffers. If one bypasses stdio and uses
read/write, the programmer can call tcdrain() to ensure the data
has been transmitted or set VMIN=1 and VTIME=0 with tcsetattr
to avoid any buffering in the kernel driver.
getting feedback when there has been a pause since the last
received character, and other such things. AFAIK these are not
available with standard Linux serial port handling.
The poll(2) system call can be used for this purpose, as it
can timeout if there is no character received within a
specified interval.
I guess I am used to microcontroller programming - things happen far
more directly and efficiently there. (Or I use Python, were the source
code is simple and easy, and you don't think about the layers in between
the code and the hardware!)
"Efficiently" with respect to what? One could argue that MCUs
waste a lot of CPU cycles because their software is usually
terribly unsophisticated. A blocking system calll like `poll`
allows the operating system to context switch to some other
runnable task while the poll is pending, without the complexity
of directly handling interrupts.
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 19:39, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 23/06/2026 17:35, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 22/06/2026 16:56, Scott Lurndal wrote:
Michael S <already5chosen@yahoo.com> writes:
On Sun, 21 Jun 2026 12:18:39 +0200
David Brown <david.brown@hesbynett.no> wrote:
or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
Which describes several long-obsolete API implementations.
OK.
But there is still termio stuff needed in the setup of the UART, when
all that is needed in almost all cases this century is picking the baud >>>> rate, possibly enabling the RTS line as an RS-485 driver enable, picking >>>> 8,n,1 (other options are rare, but not quite non-existent), and then
reading and writing characters.
I would separate those into two distinct operations:
Yes.
- One-time setup. Setting the line characteristics (baud rate,
stop-bits, parity) and the UART characteristics (flow
control, Rx and Tx FIFOs, Carrier Detect). For which there
are standard POSIX interfaces (tcsetattr/tcgetattr)
- steady-state operations, such as reading and writing which
use the normal file I/O operations (read, write, poll, et alia)
Agreed.
It's only the setup that is a pain because of legacy terminal support.
Is it really that hard?
struct termios term;
memset(&term, 0, sizeof(term));
cfmakeraw(&term); // BSD extension
cfsetispeed(&term, B38400);
cfsetospeed(&term, B38400);
term.c_cflag |= CS8 | CREAD | CRTSCTS;
tcsetattr(fd, TCSANOW, &term)
Of course, on plan 9, it's even easier:
echo -n b38400 l8 pn s1 >/dev/eia1ctl
On 23/06/2026 22:00, Michael S wrote:
On Tue, 23 Jun 2026 21:07:48 +0200
David Brown <david.brown@hesbynett.no> wrote:
And of the perhaps 20 or 30 microcontroller families I have used
over the years, I don't remember ever having seen one with a UART
that is 16550 compatible. (I did, on a couple of boards, use a
dedicated 16x50 UART chip, possibly a 16450.)
I think, I had seen one, in the early 2000, on IBM PPC 4xx embedded
chip. Whether it should be considered MCU or embedded processor is a
matter of opinion. But it was pretty low end chip, esp.
comparatively to PowerQUICC I that I was used to back in this era.
I know of the PPC 4xx series, but never used one. The PPC
microcontrollers I used first were in the 5xx series - PPC506, if I
remember correctly, then perhaps PPC561. (This is from memory, so I
might have the numbers wrong.)
And then a couple in the 5xxx
families.
One of those had two cores, and was my first use of ASMP in
a microcontroller. All the devices I used had microcontroller-style
UARTs.
Other than that I agree. It seems that Dan Cross has no [1st-hand programming] experience with MCUs.
In article <20260623224836.00001a3c@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
On Tue, 23 Jun 2026 07:25:56 +0200
David Brown <david.brown@hesbynett.no> wrote:
[snip]
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud
rate, stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just
like any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation:
<https://docs.kernel.org/driver-api/serial/driver.html> or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a total mess - it's all for handling serial terminals from the
1970's. Most of it is, of course, just a one-off setting - once you
have got the termio stuff right,
Configuration API sometimes matters.
In particular, support for various timeouts in termio is subpar
relatively to what you have in Windows. May be, Windows has too many
of them, esp. on the transmit side, but termios certainly has too
few. What is even worse, is resolution. Out of memory, resolution of >timeouts in termios is 0.1 sec. For SCADA-style protocols that's
useless.
So, it seems, the only way to implement such protocols on Linux or
similar OSes, is to read one character at time by very high priority >thread. And to pray for good luck.
Today, with many cores available everiwhere, the chance for ending up
lucky is decent. 25 years ago - less so.
That was not your original complaint, which was about how
complecting the serial port abstraction with the TTY layer
ultimtely proved to be a poor design choice. You are correct
about that, for the record, but this complaint is a different
matter entirely.
What you're saying is that you really just want to get the TTY
layer out of the path between the user program and the serial
device. That's fine, but different.
and haven't accidentally got some
extra character translation or flow control, then it's just simple
reads and writes.
Of course it is hard to remove stuff once it is there - user space
APIs are, rightly, as stable as they possibly can be.
But it is possible to add better API without removing old stuff.
May be, it even exists. I didn't follow the field since ~2021.
I'd suggest reviewing the landscape more thoroughly. This may
be a good start: https://www.youtube.com/watch?v=g4sZUBS57OQ
- Dan C.
On Wed, 24 Jun 2026 08:32:08 +0200
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 22:00, Michael S wrote:
On Tue, 23 Jun 2026 21:07:48 +0200
David Brown <david.brown@hesbynett.no> wrote:
And of the perhaps 20 or 30 microcontroller families I have used
over the years, I don't remember ever having seen one with a UART
that is 16550 compatible. (I did, on a couple of boards, use a
dedicated 16x50 UART chip, possibly a 16450.)
I think, I had seen one, in the early 2000, on IBM PPC 4xx embedded
chip. Whether it should be considered MCU or embedded processor is a
matter of opinion. But it was pretty low end chip, esp.
comparatively to PowerQUICC I that I was used to back in this era.
I know of the PPC 4xx series, but never used one. The PPC
microcontrollers I used first were in the 5xx series - PPC506, if I
remember correctly, then perhaps PPC561. (This is from memory, so I
might have the numbers wrong.)
I am pretty sure that you are wrong.
IBM and their licensees did not make 5xx core. Only Moto/Freescale/NXP
made such parts. But they call their cores MPC rather than PPC.
And then a couple in the 5xxx
families.
Here I am less than 100% sure, but 90% sure that the same applies to
5xxx. Most likely your device was called MPC rather than PPC.
One of those had two cores, and was my first use of ASMP in
a microcontroller. All the devices I used had microcontroller-style
UARTs.
Other than that I agree. It seems that Dan Cross has no [1st-hand
programming] experience with MCUs.
On Wed, 24 Jun 2026 12:18:51 -0000 (UTC)
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
In article <20260623224836.00001a3c@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
On Tue, 23 Jun 2026 07:25:56 +0200
David Brown <david.brown@hesbynett.no> wrote:
[snip]
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud
rate, stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just
like any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation:
<https://docs.kernel.org/driver-api/serial/driver.html> or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a total mess - it's all for handling serial terminals from the
1970's. Most of it is, of course, just a one-off setting - once you
have got the termio stuff right,
Configuration API sometimes matters.
In particular, support for various timeouts in termio is subpar
relatively to what you have in Windows. May be, Windows has too many
of them, esp. on the transmit side, but termios certainly has too
few. What is even worse, is resolution. Out of memory, resolution of
timeouts in termios is 0.1 sec. For SCADA-style protocols that's
useless.
So, it seems, the only way to implement such protocols on Linux or
similar OSes, is to read one character at time by very high priority
thread. And to pray for good luck.
Today, with many cores available everiwhere, the chance for ending up
lucky is decent. 25 years ago - less so.
That was not your original complaint, which was about how
complecting the serial port abstraction with the TTY layer
ultimtely proved to be a poor design choice. You are correct
about that, for the record, but this complaint is a different
matter entirely.
What you're saying is that you really just want to get the TTY
layer out of the path between the user program and the serial
device. That's fine, but different.
Concept of layers is too abstract for my poor mind.
Especially when there are more than 2 or 3 of them.
and haven't accidentally got some
extra character translation or flow control, then it's just simple
reads and writes.
Of course it is hard to remove stuff once it is there - user space
APIs are, rightly, as stable as they possibly can be.
But it is possible to add better API without removing old stuff.
May be, it even exists. I didn't follow the field since ~2021.
I'd suggest reviewing the landscape more thoroughly. This may
be a good start: https://www.youtube.com/watch?v=g4sZUBS57OQ
- Dan C.
I don't consume technical stuff in video form.
Is it available as a written document?
[ ... ]
So, it seems, the only way to implement such protocols on Linux or
similar OSes, is to read one character at time by very high priority
thread. And to pray for good luck.
Today, with many cores available everiwhere, the chance for ending up
lucky is decent. 25 years ago - less so.
Both the slides and a transcript are linked in the video description.
On 6/23/2026 7:05 PM, Lawrence D?Oliveiro wrote:
On Tue, 23 Jun 2026 14:41:28 -0700, Chris M. Thomasson wrote:
I think its a rather low level way to make high end
servers/clients akin to dx12/vulkan vs modern opengl?
No. Async I/O is all about performance. Whereas a programmable
shader pipeline is all about versatility.
But take a look on how to have to use io_uring?
On 24/06/2026 12:47, Dan Cross wrote:
In article <111eli4$2g1qh$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 19:12, Dan Cross wrote:
In article <111eavb$2c615$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 17:35, Scott Lurndal wrote:
It's aI'm sure that the microprocessors you routinely use all still
total mess - it's all for handling serial terminals from the 1970's. >>>>>>
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have
UARTs that have register sets compatible with them, but I don't think it >>>>> is common. Microcontrollers certainly don't make any attempt to have >>>>> compatibility with those register sets.
This is simply incorrect. Lots of parts still have integrated
16550-compatible UARTs; the designware part that is common in a
lot of SoC's will even go up to 3MBAUD.
I don't know all embedded microprocessors. I suspect that in order to
remain as "PC compatible" as possible, x86 SoC's might have 16550
compatible UARTs.
Essentially every modern x86 SoC has at least one; usually
several. They may or may not be lined out, but they're there.
Fair enough.
But x86 SoC's are a tiny fraction of SoC or embedded processors, which
are predominantly ARM based. And microcontrollers are orders of
magnitude more common than processors, embedded or not.
Assuming you are correct (and I have no reason to doubt it, but have not >checked independently) that modern x86 SoCs have 16550 UARTs, then they
are by definition not obsolete. But in pretty much all other devices, >built-in UARTs are not 16550 compatible because there are no benefits in >doing that, while alternative designs are significantly better (in
various possible ways).
So "obsolete" was an exaggeration. But I think if you were to make a
list of the top hundred microcontrollers and microprocessor SoCs, order
by the number of devices shipped during the last few years, I do not
expect you'd see more than a few low down in the list that had a 16550 UART.
(Scott also mentioned PL011 UARTs, which I did not discuss - these are
ARM designs and thus common in some ARM microprocessors, though not in
ARM microcontrollers. They are also not found in most industrial ARM
SoCs, such as the i.mx families - makers of such chips already have
their own peripheral device IPs, which they use. The PL011, from the
quick look I had, seems a reasonable enough UART for many purposes, with >support for DMA and timeouts. It appears to lack RS-485 support, but >perhaps I missed some details.)
Some other systems may use 16550-compatible parts as well; as I
mentioned, DesignWare markets one as an embeddable piece of IP
that one can incorporate into one's own design.
There are countless 16550 (or 8250, or similar) models available under a >variety of licenses.
Many others do not. The NXP i.mx family, which is one of the most
popular in industrial usage, have UARTs that do not have 16550 register
sets. There is a reason linux/drivers/tty/serial has several dozen C
files, supporting several dozen UARTs. Critically, embedded UARTs
(excluding 16550 compatible ones) support DMA.
I did not say that other systems used 16550, I was disputing the
incorrect statement that "16550 UARTs are long obsolete." If
you mean discrete UART chips signaling at TTL levels, whether
shifted to RS-232 levels or not, you're correct, but I took your
statement to be more general. Simply, they are not obsolete at
all, and they're extraordinarily common.
I accept that they exist - I dispute that they are common, at least
viewed in relation to the types of microprocessor SoCs or
microcontrollers currently available, or in terms of numbers shipped.
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated 16x50
UART chip, possibly a 16450.)
Ok, but your personal experience is anecdotal and by your own
admission not representative of large machines. Judging that
the obsolesence (or not) of a part based on your own experience
alone is not a great way to make judgements about these things.
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >more (from my attempts at googling - noting that you don't get real, >concrete figures without paying real, concrete money to marketing and >analysis companies). There are also devices where the core is neither
ARM nor x86. None of these, as a rule, have 16550's - they have much
better UARTs. (For small microcontrollers, "better" can mean smaller
and lower power, rather than necessarily additional useful features.)
Remember, the sole reason anyone would want to use a 16550 is
compatibility with code that expects a 16550. And that means, to a very >large extent, old x86 code or newer x86 code that is written to be >compatible with the old code and hardware.
[snip personal experience]
Of course, there are and have been others; I've personally
worked with Zilog and Motorola parts in addition to the
aforementioned two.
To be clear here, you are saying you have worked with microprocessors or >microcontrollers with other kinds of UARTs than 16550's or PL011's ? Or
with other stand-alone UART chips?
I know both Motorola and Zilog
produced stand-alone UART chips, and I know Motorola (then Freescale,
now part of NXP) have made a countless number of processors and >microcontrollers with built-in UARTs that are not 16550 compatible.
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF, >>>>> or hardware flow control (the RTS signal is often used for RS-485 drive >>>>> enable), and regularly use 3 MBaud for local connections to fast
microcontrollers.
I use 3MBAUD, 16550-compatible UARTs embedded in AMD's EPYC SoCs
daily. We use hardware flow control to avoid dropping
characters when speaking to a fast uctlr running our own
embedded OS. The DW part in the SoC even supports auto HW flow
control and manages the FIFOs and signaling more or less
independently of the host (which actually caused a problem in
our driver a few months back).
If reliable delivery of data is important to you, some kind of
flow control is useful, whether hardware or software based. If
it's just for debug spew, you may not care.
If your systems are fast enough, and you have the right priorities for
your threads, interrupts, DMAs, etc., then you don't need flow control.
And most protocols (other than debug outputs) used over serial ports in
embedded systems are not continuous traffic flows - you have packets,
and typically have request/response patterns. As long as you have DMA
to give you FIFOs that are big enough, you can consider the packet
reception and answering as high-level software flow control.
Again, extrapolating from your own personal experience to other
areas is leading to a specious conclusion. You hinted at the
issue: _if_ your systems can keep up, you may be ok. But on a
large system, running a multiuser multitasking operating system,
doing a ton of IO on high speed devices, dealing with many
thousands of interrupts a second across many cores, you may not
be able to keep up.
Of course you can, if that's what you want to do with the system.
A Gbit network interface generates thousands of interrupts a second. But
is entirely fair to say that general purpose OS's, and x86 hardware, are
not well suited to quick reactions and low or predictable latencies.
Throughput is usually not an issue, but accurate timing is hard to
achieve. It is not without reason that many embedded systems have a
Linux SOM for networking and high-level decisions, and microcontrollers
for the fast reaction and deterministic control stuff. (Many SoC's >targetting industrial embedded Linux have microcontrollers in the SoC >itself.) And it is also fair to say that if you want to have demanding >serial port usage on a general-purpose OS, you want a decent, modern
UART rather than an old-fashioned 16550.
On 24/06/2026 13:04, Dan Cross wrote:
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
[snip]
Agreed.
It's only the setup that is a pain because of legacy terminal support.
Is it really that hard?
struct termios term;
memset(&term, 0, sizeof(term));
cfmakeraw(&term); // BSD extension
cfsetispeed(&term, B38400);
cfsetospeed(&term, B38400);
term.c_cflag |= CS8 | CREAD | CRTSCTS;
tcsetattr(fd, TCSANOW, &term)
It took a good deal more than that when I did it. But it is certainly >possible that my reference sources for the task were not the best
available. Note also that it's not just the number of lines of C code - >it's knowing what those lines are, what settings you need, which headers
to find the declarations, etc.
[snip]
I guess I am used to microcontroller programming - things happen far
more directly and efficiently there. (Or I use Python, were the source
code is simple and easy, and you don't think about the layers in between >>> the code and the hardware!)
"Efficiently" with respect to what? One could argue that MCUs
waste a lot of CPU cycles because their software is usually
terribly unsophisticated. A blocking system calll like `poll`
allows the operating system to context switch to some other
runnable task while the poll is pending, without the complexity
of directly handling interrupts.
No, I don't think you can argue that at all - sophisticated software at
the OS level wastes as many cycles as sophisticated software at the >application level.
In my microcontroller programming, the serial handling is as
sophisticated or simple as I need it to be. It could be application
code reading and writing hardware registers directly, with busy-waiting >loops. More likely data is transferred into or out of DMA based ring >buffers that feed the UART.
What I don't have is layers of possible translations because the user
might be connecting to a VT100, or expecting the driver to handle
backspace and XON/XOFF.
I don't have to pass data up and down through
the VFS and devfs, checking user permissions, or system calls that have
to check everything coming from user space. I realise that a lot of
this is necessary in Linux (or any other general-purpose OS) - you can't >make a system safe for multiple users and multiple programmers without
lots of checks, and you can't allow "echo Hello > /dev/ttyUSB0" without
lots of abstraction.
Directly handling interrupts in a microcontroller is not particularly >complex - it's daily work for microcontroller developers.
And we too know how to have blocking calls and multiple threads.
On Wed, 24 Jun 2026 12:18:51 -0000 (UTC)
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
In article <20260623224836.00001a3c@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
On Tue, 23 Jun 2026 07:25:56 +0200
David Brown <david.brown@hesbynett.no> wrote:
[snip]
The POSIX serial interface seems quite useful - using ioctl(2)
to handle non-data-transfer interfaces (e.g. setting the baud
rate, stop bits, parity, et alia) via library functions
(tcsetattr/tcgetattr) and using standard filesystem calls for
reading and writing.
Once the serial port is opened, it is a simple byte stream just
like any other unix file.
Bitbanging RS232C for SCADA was never a design goal, unlike
IEEE 488.
Just look at the documentation:
<https://docs.kernel.org/driver-api/serial/driver.html> or
<https://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux>.
It's a total mess - it's all for handling serial terminals from the
1970's. Most of it is, of course, just a one-off setting - once you
have got the termio stuff right,
Configuration API sometimes matters.
In particular, support for various timeouts in termio is subpar
relatively to what you have in Windows. May be, Windows has too many
of them, esp. on the transmit side, but termios certainly has too
few. What is even worse, is resolution. Out of memory, resolution of
timeouts in termios is 0.1 sec. For SCADA-style protocols that's
useless.
So, it seems, the only way to implement such protocols on Linux or
similar OSes, is to read one character at time by very high priority
thread. And to pray for good luck.
Today, with many cores available everiwhere, the chance for ending up
lucky is decent. 25 years ago - less so.
That was not your original complaint, which was about how
complecting the serial port abstraction with the TTY layer
ultimtely proved to be a poor design choice. You are correct
about that, for the record, but this complaint is a different
matter entirely.
What you're saying is that you really just want to get the TTY
layer out of the path between the user program and the serial
device. That's fine, but different.
Concept of layers is too abstract for my poor mind.
Especially when there are more than 2 or 3 of them.
and haven't accidentally got some
extra character translation or flow control, then it's just simple
reads and writes.
Of course it is hard to remove stuff once it is there - user space
APIs are, rightly, as stable as they possibly can be.
But it is possible to add better API without removing old stuff.
May be, it even exists. I didn't follow the field since ~2021.
I'd suggest reviewing the landscape more thoroughly. This may
be a good start: https://www.youtube.com/watch?v=g4sZUBS57OQ
I don't consume technical stuff in video form.
Is it available as a written document?
In article <111gkgm$2vhih$1@dont-email.me>,<snip>
David Brown <david.brown@hesbynett.no> wrote:
A Gbit network interface generates thousands of interrupts a second. But >>is entirely fair to say that general purpose OS's, and x86 hardware, are >>not well suited to quick reactions and low or predictable latencies.
In article <20260624220010.00006ed7@yahoo.com>,
Michael S <already5chosen@yahoo.com> wrote:
Concept of layers is too abstract for my poor mind.
Especially when there are more than 2 or 3 of them.
Huh.
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 12:47, Dan Cross wrote:
In article <111eli4$2g1qh$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 19:12, Dan Cross wrote:
In article <111eavb$2c615$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 23/06/2026 17:35, Scott Lurndal wrote:
It's aI'm sure that the microprocessors you routinely use all still
total mess - it's all for handling serial terminals from the 1970's. >>>>>>>
support either the 16550 UART or the PL011 for debug purposes
if not for production purposes. Our most recently taped out
chip has a dozen pl011 compatible UARTS.
16550 UARTs are long obsolete. Some embedded processors might have >>>>>> UARTs that have register sets compatible with them, but I don't think it >>>>>> is common. Microcontrollers certainly don't make any attempt to have >>>>>> compatibility with those register sets.
This is simply incorrect. Lots of parts still have integrated
16550-compatible UARTs; the designware part that is common in a
lot of SoC's will even go up to 3MBAUD.
I don't know all embedded microprocessors. I suspect that in order to >>>> remain as "PC compatible" as possible, x86 SoC's might have 16550
compatible UARTs.
Essentially every modern x86 SoC has at least one; usually
several. They may or may not be lined out, but they're there.
Fair enough.
But x86 SoC's are a tiny fraction of SoC or embedded processors, which
are predominantly ARM based. And microcontrollers are orders of
magnitude more common than processors, embedded or not.
Again, not something I was commenting on. Low(er) volume !=
obsolete.
Assuming you are correct (and I have no reason to doubt it, but have not
checked independently) that modern x86 SoCs have 16550 UARTs, then they
are by definition not obsolete. But in pretty much all other devices,
built-in UARTs are not 16550 compatible because there are no benefits in
doing that, while alternative designs are significantly better (in
various possible ways).
There are things I do not like about the 8250-series UARTs, but
I do not know what criteria you are using to judge the relative
merits of the 16550 versus alternatives. Given that you don't
use them, one wonders what your basis for comparison is, as
well.
So "obsolete" was an exaggeration. But I think if you were to make a
list of the top hundred microcontrollers and microprocessor SoCs, order
by the number of devices shipped during the last few years, I do not
expect you'd see more than a few low down in the list that had a 16550 UART.
Perhaps? But also irrelevant.
(Scott also mentioned PL011 UARTs, which I did not discuss - these are
ARM designs and thus common in some ARM microprocessors, though not in
ARM microcontrollers. They are also not found in most industrial ARM
SoCs, such as the i.mx families - makers of such chips already have
their own peripheral device IPs, which they use. The PL011, from the
quick look I had, seems a reasonable enough UART for many purposes, with
support for DMA and timeouts. It appears to lack RS-485 support, but
perhaps I missed some details.)
I just checked and it looks like ST ships PL011's in a bunch of
Cortex-M class parts.
Of course, there are a ton of ARM
microcontrollers, but if you reread Scott's message (again) he
mentions mircoprocessors, not specificially uctlr's.
Some other systems may use 16550-compatible parts as well; as I
mentioned, DesignWare markets one as an embeddable piece of IP
that one can incorporate into one's own design.
There are countless 16550 (or 8250, or similar) models available under a
variety of licenses.
Yes.
Many others do not. The NXP i.mx family, which is one of the most
popular in industrial usage, have UARTs that do not have 16550 register >>>> sets. There is a reason linux/drivers/tty/serial has several dozen C
files, supporting several dozen UARTs. Critically, embedded UARTs
(excluding 16550 compatible ones) support DMA.
I did not say that other systems used 16550, I was disputing the
incorrect statement that "16550 UARTs are long obsolete." If
you mean discrete UART chips signaling at TTL levels, whether
shifted to RS-232 levels or not, you're correct, but I took your
statement to be more general. Simply, they are not obsolete at
all, and they're extraordinarily common.
I accept that they exist - I dispute that they are common, at least
viewed in relation to the types of microprocessor SoCs or
microcontrollers currently available, or in terms of numbers shipped.
That's fine, but I made no statement about that.
And of the perhaps 20 or 30 microcontroller families I have used over
the years, I don't remember ever having seen one with a UART that is
16550 compatible. (I did, on a couple of boards, use a dedicated 16x50 >>>> UART chip, possibly a 16450.)
Ok, but your personal experience is anecdotal and by your own
admission not representative of large machines. Judging that
the obsolesence (or not) of a part based on your own experience
alone is not a great way to make judgements about these things.
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or
more (from my attempts at googling - noting that you don't get real,
concrete figures without paying real, concrete money to marketing and
analysis companies). There are also devices where the core is neither
ARM nor x86. None of these, as a rule, have 16550's - they have much
better UARTs. (For small microcontrollers, "better" can mean smaller
and lower power, rather than necessarily additional useful features.)
term% uname -a
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
Remember, the sole reason anyone would want to use a 16550 is
compatibility with code that expects a 16550. And that means, to a very
large extent, old x86 code or newer x86 code that is written to be
compatible with the old code and hardware.
Sure. I'm sure there are any number of reasons why a vendor
would pick any given type of UART; software compatibility with
existing drivers is surely one of them.
[snip personal experience]
Of course, there are and have been others; I've personally
worked with Zilog and Motorola parts in addition to the
aforementioned two.
To be clear here, you are saying you have worked with microprocessors or
microcontrollers with other kinds of UARTs than 16550's or PL011's ? Or
with other stand-alone UART chips?
Yes to both. In this case, I am referring specifically to
discrete UART parts from both vendors.
I know both Motorola and Zilog
produced stand-alone UART chips, and I know Motorola (then Freescale,
now part of NXP) have made a countless number of processors and
microcontrollers with built-in UARTs that are not 16550 compatible.
I don't know what the latter has to do with the former, or the
larger discussion. You seem to be discussing something that I
never said or implied.
FTR I am saying I have used discrete UART parts from both Zilog
(Zilog UARTs used to be common in Sun workstations) and Motorola
(they had a reasonable DUART that worked well with 68k).
Sure, the modem signals are obsolete and not often used.
With 115k baud, it's less likely that the hardware flow
control signals (RTS/CTS) are still used (although XON/XOFF is
still useful) in most cases, but the classic serial port still
lives and is useful, particularly in embedded hardware.
I use serial ports all the time. I've never had any use for XON/XOFF, >>>>>> or hardware flow control (the RTS signal is often used for RS-485 drive >>>>>> enable), and regularly use 3 MBaud for local connections to fast
microcontrollers.
I use 3MBAUD, 16550-compatible UARTs embedded in AMD's EPYC SoCs
daily. We use hardware flow control to avoid dropping
characters when speaking to a fast uctlr running our own
embedded OS. The DW part in the SoC even supports auto HW flow
control and manages the FIFOs and signaling more or less
independently of the host (which actually caused a problem in
our driver a few months back).
If reliable delivery of data is important to you, some kind of
flow control is useful, whether hardware or software based. If
it's just for debug spew, you may not care.
If your systems are fast enough, and you have the right priorities for >>>> your threads, interrupts, DMAs, etc., then you don't need flow control. >>>>
And most protocols (other than debug outputs) used over serial ports in >>>> embedded systems are not continuous traffic flows - you have packets,
and typically have request/response patterns. As long as you have DMA >>>> to give you FIFOs that are big enough, you can consider the packet
reception and answering as high-level software flow control.
Again, extrapolating from your own personal experience to other
areas is leading to a specious conclusion. You hinted at the
issue: _if_ your systems can keep up, you may be ok. But on a
large system, running a multiuser multitasking operating system,
doing a ton of IO on high speed devices, dealing with many
thousands of interrupts a second across many cores, you may not
be able to keep up.
Of course you can, if that's what you want to do with the system.
No, not really.
Perhaps in the uctlr world that is true, but in that world
workloads tend to be fixed and predictible; in the world of
large systems, things are far more dynamic. Interrupts can, and
do, get lost; FIFOs get full; data can get corrupted; flow
control and synchronization between endpoints in a
communications protocol is useful.
Perhaps that doesn't matter for your use cases, and you've never
needed it; but don't extrapolate to other use cases you have no
experience with.
A Gbit network interface generates thousands of interrupts a second. But
is entirely fair to say that general purpose OS's, and x86 hardware, are
not well suited to quick reactions and low or predictable latencies.
The hardware is fine. It's the OS that usually struggles
because there may be more load on the machine than can
reasonably be accommodated.
Throughput is usually not an issue, but accurate timing is hard to
achieve. It is not without reason that many embedded systems have a
Linux SOM for networking and high-level decisions, and microcontrollers
for the fast reaction and deterministic control stuff. (Many SoC's
targetting industrial embedded Linux have microcontrollers in the SoC
itself.) And it is also fair to say that if you want to have demanding
serial port usage on a general-purpose OS, you want a decent, modern
UART rather than an old-fashioned 16550.
Again, you haven't specified what's "old-fashioned" about it, or
what makes alternatives superior; on modern systems, this is not
your father's 8250. Modern SoCs support DMA and MMIO accesses
for UARTs and speeds up to 3MBAUD or more, even if the registers
are the same 'ol 16550 registers since the 486 era (with some
extensions, of course).
Beyond that, you're correct that many modern SoCs have embedded microcontrollers capable of real-time response; yay. Using one
just to avoid flow control over a serial protocol seems like
going to extremes to avoid a simple thing. As I mentioned, the
DW part even does CTS/RTS HW flow control automatically, without
software intervention.
This is hardly an obsolete part in any measurable sense, and
arguments about the volume of microcontrollers using other parts
don't make it obsolete.
- Dan C.
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >>> more (from my attempts at googling - noting that you don't get real,
concrete figures without paying real, concrete money to marketing and
analysis companies). There are also devices where the core is neither
ARM nor x86. None of these, as a rule, have 16550's - they have much
better UARTs. (For small microcontrollers, "better" can mean smaller
and lower power, rather than necessarily additional useful features.)
term% uname -a
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling >rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >>>> more (from my attempts at googling - noting that you don't get real,
concrete figures without paying real, concrete money to marketing and
analysis companies). There are also devices where the core is neither >>>> ARM nor x86. None of these, as a rule, have 16550's - they have much
better UARTs. (For small microcontrollers, "better" can mean smaller
and lower power, rather than necessarily additional useful features.)
term% uname -a
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
The dw16550 is synopsys (DW_apb_uart) optimized for the ARM
APB bus. It's modeled on the 16550 for backward compatability
yet includes additional features from 16650 and 16750 designs
using MMIO registers rather than the x86 I/O space registers.
It seems to be popular in some DSUs (e.g. Marvell Armada).
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling
rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
There are various techniques to moderate the interrupt frequency
at high packet arrival rates. Usually based on a packet-count + timer; the interrupt fires after the specified number of packets has arrived
or the timer has expired.
In article <111gm0p$2vhih$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 13:04, Dan Cross wrote:
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
[snip]
Agreed.
It's only the setup that is a pain because of legacy terminal support.
Is it really that hard?
struct termios term;
memset(&term, 0, sizeof(term));
cfmakeraw(&term); // BSD extension
cfsetispeed(&term, B38400);
cfsetospeed(&term, B38400);
term.c_cflag |= CS8 | CREAD | CRTSCTS;
tcsetattr(fd, TCSANOW, &term)
It took a good deal more than that when I did it. But it is certainly
possible that my reference sources for the task were not the best
available. Note also that it's not just the number of lines of C code -
it's knowing what those lines are, what settings you need, which headers
to find the declarations, etc.
One presumes that you if you are using, say, the POSIX
interfaces, you'll have some idea of how to write code for POSIX
and have access to a reference. My system's man pages are
reasonable for the latter.
[snip]
I guess I am used to microcontroller programming - things happen far
more directly and efficiently there. (Or I use Python, were the source >>>> code is simple and easy, and you don't think about the layers in between >>>> the code and the hardware!)
"Efficiently" with respect to what? One could argue that MCUs
waste a lot of CPU cycles because their software is usually
terribly unsophisticated. A blocking system calll like `poll`
allows the operating system to context switch to some other
runnable task while the poll is pending, without the complexity
of directly handling interrupts.
No, I don't think you can argue that at all - sophisticated software at
the OS level wastes as many cycles as sophisticated software at the
application level.
Again, I ask, "efficiently" with respect to what? Note what I
said: "One could argue that MCUs waste a lot of CPU cycles
because their software _is usually terribly unsophisticated_":
emphasis added.
In my microcontroller programming, the serial handling is as
sophisticated or simple as I need it to be. It could be application
code reading and writing hardware registers directly, with busy-waiting
loops. More likely data is transferred into or out of DMA based ring
buffers that feed the UART.
What I don't have is layers of possible translations because the user
might be connecting to a VT100, or expecting the driver to handle
backspace and XON/XOFF.
You are conflating the TTY layer in Unix-style systems with the
serial port driver, specifically. I will acknowledge that this
is a problem; a TTY-abstraction might have made sense in the
1970s ("VT100?! Luxury. I'm stuck with an ASR Model 37
teletype...."), but does not make a lot of sense now, but that
does not mean that large systems _need_ to use that metaphor.
See the Plan 9 examples I keep sprinkling around; that system
doesn't have a TTY abstraction at all.
I don't have to pass data up and down through
the VFS and devfs, checking user permissions, or system calls that have
to check everything coming from user space. I realise that a lot of
this is necessary in Linux (or any other general-purpose OS) - you can't
make a system safe for multiple users and multiple programmers without
lots of checks, and you can't allow "echo Hello > /dev/ttyUSB0" without
lots of abstraction.
The purpose of an operating system is to control hardware,
isolate software principles from one another, and provide useful
programming abstractions. Essentially what you're saying is
that you don't want or need that, for some kinds of programs.
That's fine. But to extrapolate from that to, "and this
category of software is more efficient", as an absolute
statement, is what I take exception to: there's too much
disconfirming evidence to the contrary. Perhaps not in the
programs you personally write, but I took your statement was
general and not restricted to only those programs.
Directly handling interrupts in a microcontroller is not particularly
complex - it's daily work for microcontroller developers.
Yes, because if your needs are not as general as those demanded
by general purposes operating systems on general purpose CPUs,
it can be made reasonably simple.
As I mentioned, most (not
all) programs that target microcontrollers are not terribly
sophisticated, and have very modest requirements in this regard.
And we too know how to have blocking calls and multiple threads.
...and there are embedded OSes that have system calls and
privileged modes that restrict access to the hardware, too. :-}
On Wed, 24 Jun 2026 04:36:20 -0700, Chris M. Thomasson wrote:
On 6/23/2026 7:05 PM, Lawrence D?Oliveiro wrote:
On Tue, 23 Jun 2026 14:41:28 -0700, Chris M. Thomasson wrote:
I think its a rather low level way to make high end
servers/clients akin to dx12/vulkan vs modern opengl?
No. Async I/O is all about performance. Whereas a programmable
shader pipeline is all about versatility.
But take a look on how to have to use io_uring?
Except you don?t (usually) have to use io_uring, as I already showed.
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
Embedded ARM systems outship embedded x86 systems by a factor of
1000 or more (from my attempts at googling - noting that you
don't get real, concrete figures without paying real, concrete
money to marketing and analysis companies). There are also
devices where the core is neither ARM nor x86. None of these, as
a rule, have 16550's - they have much better UARTs. (For small
microcontrollers, "better" can mean smaller and lower power,
rather than necessarily additional useful features.)
term% uname -a
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the >example. Where is this riscv core from?
The dw16550 is synopsys (DW_apb_uart) optimized for the ARM
APB bus. It's modeled on the 16550 for backward compatability
yet includes additional features from 16650 and 16750 designs
using MMIO registers rather than the x86 I/O space registers.
It seems to be popular in some DSUs (e.g. Marvell Armada).
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using
polling rather than interrupts to avoid context switches. But that
is definitely outside my experience.)
There are various techniques to moderate the interrupt frequency
at high packet arrival rates. Usually based on a packet-count +
timer; the interrupt fires after the specified number of packets has
arrived or the timer has expired.
BGB <cr88192@gmail.com> writes:
[...]
Then again, going into the weeds on this:
Would, say:
cd ftp://foo.org/pub/
ls
Even really make sense?...
It wouldn't work that way, because "ftp:" is a valid name for a
directory on a Unix-like system, and "//" is equivalent to "/".
$ cd ftp://foo.org/pub/
$ ls
this-is-not-an-ftp-server
$
Trying to be at least vaguely topical, on systems with a more
restrictive file name syntax it might be possible for fopen() to
distinguish by name between a local file and a URL, but not on a
Unix-like system without more information.
Or, would it be better to ask people to at least mount it into the VFS
or similar?...
It's certainly possible to mount an ftp server as a filesystem on
most Unix-like systems, probably with some add-on software
(like curlftpfs, which I haven't tried).
[...]
On 25/06/2026 20:29, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
term% uname -a
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >>>>> more (from my attempts at googling - noting that you don't get real, >>>>> concrete figures without paying real, concrete money to marketing and >>>>> analysis companies). There are also devices where the core is neither >>>>> ARM nor x86. None of these, as a rule, have 16550's - they have much >>>>> better UARTs. (For small microcontrollers, "better" can mean smaller >>>>> and lower power, rather than necessarily additional useful features.) >>>>
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
The dw16550 is synopsys (DW_apb_uart) optimized for the ARM
APB bus. It's modeled on the 16550 for backward compatability
yet includes additional features from 16650 and 16750 designs
using MMIO registers rather than the x86 I/O space registers.
It seems to be popular in some DSUs (e.g. Marvell Armada).
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling
rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
There are various techniques to moderate the interrupt frequency
at high packet arrival rates. Usually based on a packet-count + timer; the >> interrupt fires after the specified number of packets has arrived
or the timer has expired.
Basically, a FIFO at the packet level, in the same way that byte FIFOs
work for UARTs ? I am sure that is a very good idea, especially for the >higher speed interfaces. I don't see a problem with thousands of
interrupts a second for 1 Gbps networking,
but I do not see it going so
well when scaling by a factor of 100 for 100 Gpbs!
And for even higher
rates, I believe it is common to have various kinds of accelerators
tightly integrated with the network interface, further reducing the work
(or at least the latency challenges) for the host.
But again, those are
not things I have done myself.
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 20:29, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
term% uname -a
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >>>>>> more (from my attempts at googling - noting that you don't get real, >>>>>> concrete figures without paying real, concrete money to marketing and >>>>>> analysis companies). There are also devices where the core is neither >>>>>> ARM nor x86. None of these, as a rule, have 16550's - they have much >>>>>> better UARTs. (For small microcontrollers, "better" can mean smaller >>>>>> and lower power, rather than necessarily additional useful features.) >>>>>
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
The dw16550 is synopsys (DW_apb_uart) optimized for the ARM
APB bus. It's modeled on the 16550 for backward compatability
yet includes additional features from 16650 and 16750 designs
using MMIO registers rather than the x86 I/O space registers.
It seems to be popular in some DSUs (e.g. Marvell Armada).
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling >>>> rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
There are various techniques to moderate the interrupt frequency
at high packet arrival rates. Usually based on a packet-count + timer; the
interrupt fires after the specified number of packets has arrived
or the timer has expired.
Basically, a FIFO at the packet level, in the same way that byte FIFOs
work for UARTs ? I am sure that is a very good idea, especially for the
higher speed interfaces. I don't see a problem with thousands of
interrupts a second for 1 Gbps networking,
That's a lot of unnecessary overhead. Consider that at 1Gb/s,
the controller can theoretically receive 1,488,095 64-byte packets every second.
That's a million and a half interrupts per second.
but I do not see it going so
well when scaling by a factor of 100 for 100 Gpbs!
Tis truth, forsooth.
And for even higher
rates, I believe it is common to have various kinds of accelerators
tightly integrated with the network interface, further reducing the work
(or at least the latency challenges) for the host.
Indeed. Packet classification/Receive-side-scaling, handling the
various tunneling protocols, VLANs, IPSEC, MPLS et alia are all efficiently done by hardware accelerators. Something I have done myself :-)
But again, those are
not things I have done myself.
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 12:47, Dan Cross wrote:Again, not something I was commenting on. Low(er) volume !=
[snip]
obsolete.
OK. I have already accepted that "obsolete" was an exaggeration. More >appropriate would be "not suitable for new designs".
Assuming you are correct (and I have no reason to doubt it, but have not >>> checked independently) that modern x86 SoCs have 16550 UARTs, then they
are by definition not obsolete. But in pretty much all other devices,
built-in UARTs are not 16550 compatible because there are no benefits in >>> doing that, while alternative designs are significantly better (in
various possible ways).
There are things I do not like about the 8250-series UARTs, but
I do not know what criteria you are using to judge the relative
merits of the 16550 versus alternatives. Given that you don't
use them, one wonders what your basis for comparison is, as
well.
I already said that I /had/ used one, as specific external chip, on a
board. Admittedly that was a long time ago.
But regardless of how much or how little I have used them, I am entirely >capable of looking at a datasheet and judging the features a device has
or does not have. I can look at the way a peripheral is connected, and
the kind of databus it supports, the kind of inputs and outputs it has,
the registers it has, and everything else. That's an important part of
the job I do. The idea that I would have to have /used/ a device to be
able to compare it to other related devices is, frankly, bizarre.
[snip]
I just checked and it looks like ST ships PL011's in a bunch of
Cortex-M class parts.
Have you a reference for those?
[snip]
Of course, there are a ton of ARM
microcontrollers, but if you reread Scott's message (again) he
mentions mircoprocessors, not specificially uctlr's.
And if you re-read Scott's message, you'll see there's been a dozen
posts since then - mentioning other related things. We have moved on
from there.
[snip]
term% uname -a
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
I know both Motorola and Zilog
produced stand-alone UART chips, and I know Motorola (then Freescale,
now part of NXP) have made a countless number of processors and
microcontrollers with built-in UARTs that are not 16550 compatible.
I don't know what the latter has to do with the former, or the
larger discussion. You seem to be discussing something that I
never said or implied.
(As a general point, not everything people write is an immediate direct >response to what someone else wrote - nor is it necessarily disputing
what they wrote. People add extra information, anecdotes,
clarifications, questions, and digressions. Several times you have said
my comments were irrelevant, or denied saying or implying the point you >think I am disputing. My posts are not a series of attacks on what I >imagine you said. While it is entirely possible that I misunderstand or >misread something someone says, and respond to that misunderstood point, >usually if I write something that does not appear to be a direct
response to a previous point, it is not a direct response to /any/ point
- real or imagined. Conversations would quickly get boring if they
never wander a little from previous points.)
[snip]
No, not really.
Perhaps in the uctlr world that is true, but in that world
workloads tend to be fixed and predictible; in the world of
large systems, things are far more dynamic. Interrupts can, and
do, get lost; FIFOs get full; data can get corrupted; flow
control and synchronization between endpoints in a
communications protocol is useful.
I do appreciate that on "big" systems things are more dynamic and >unpredictable compared to many microcontroller systems. And yes, things
can get lost or corrupted - that is true in communications in >microcontroller systems too. As the Mythbuster's tee-shirt says,
failure is always an option. You almost always want some kind of
control, synchronisation, error checking, and retry mechanism. You
usually have several of these, at different levels of the system from
the hardware, through low-level drivers or interfaces, and up to
high-level control.
But yes, really - you /can/ handle thousands of interrupts per second on >Linux systems if you want to.
I've happily passed packets through Linux
systems at high speeds, without failures. My current system has a >microcontroller connected to a Linux SOM. My focus is on the >microcontroller software, but amongst other things I have Python code on
the PC sending UDP telegrams via the SOM (with a USB to Ethernet dongle)
to the microcontroller. I run about 2,000+ transactions a second,
without failures - where a transaction means the Linux SOM getting a
packet in, routing it out to the microcontroller, getting a reply back,
and routing that towards the PC. In the background, the SOM is
continuously bzipping and bunzipping a big file, just to have it working
on something. How many interrupts per second do you think that is?
Of course there are other patterns of interrupts that are more stressful >than the ones I have there. But then, I am running just a single core
SoC here, and the speed bottlenecks are mostly in the Python test code.
And I have done nothing towards improving the latencies or anything else
- this is a bog standard Debian ARM installation.
Perhaps that doesn't matter for your use cases, and you've never
needed it; but don't extrapolate to other use cases you have no
experience with.
I have worked on systems where we have locked interrupts and programs to >particular cores (of a 4 core SoC) to minimise jitter, with real-time >extensions in the kernel. Admittedly there were not many packets
handled in and out every millisecond, but the millisecond tick needed to
be within about 1% jitter.
Of course there are vast combinations of hardware and requirements that
I have /not/ worked with. But I have seen enough to know that you can
do a great deal with Linux even without careful tuning - and even more
with tuning. Thousands of interrupts per second is peanuts to a modern >Linux system - big or small. Tens or hundreds of thousands of
interrupts per second - then you are pushing it, and will want to
re-think things a bit. (My understanding is that for very fast network >cards on big systems, you dedicate a core to the task and using polling >rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
And certainly it is harder to do high frequency operations on Linux, and
on microprocessors, than on microcontrollers. Context switches are >massively more demanding, and you have little details like "security"
that are a different world on a multi-user system than on a
microcontroller. On one 500 MHz microcontroller I did some testing with
an RTOS doing round-robin context switches at 1 MHz, taking about 10% of
the processor capacity. I don't think you'd get far with a jiffy rate
of 1 MHz on any Linux system, big or small. And I have also had a
system where I did bit-banging of a 115200 baud UART with 4x
oversampling. That's 460,800 timer interrupts per second - on a >microcontroller running with a 18.432 MHz clock. 40 clocks per
interrupt, and time to spare for the rest of the application.
Throughput is usually not an issue, but accurate timing is hard to
achieve. It is not without reason that many embedded systems have a
Linux SOM for networking and high-level decisions, and microcontrollers
for the fast reaction and deterministic control stuff. (Many SoC's
targetting industrial embedded Linux have microcontrollers in the SoC
itself.) And it is also fair to say that if you want to have demanding
serial port usage on a general-purpose OS, you want a decent, modern
UART rather than an old-fashioned 16550.
Again, you haven't specified what's "old-fashioned" about it, or
what makes alternatives superior; on modern systems, this is not
your father's 8250. Modern SoCs support DMA and MMIO accesses
for UARTs and speeds up to 3MBAUD or more, even if the registers
are the same 'ol 16550 registers since the 486 era (with some
extensions, of course).
Well, to be fair it depends on what you want to do with the UART - and
my bias is towards industrial systems. I guess the biggest want an
RS-485 driver line - when doing faster communication, that is an
essential feature. (While I have never had the dubious pleasure of >implementing Profibus DP, it runs at 12 Mbps on RS-485.) I like better >control of FIFOs and triggers, for both interrupts and DMA. I have >occasionally had need of 9 bit characters. Sending break characters is >important in some protocols, like LIN. Automatic detection of frame
start characters can significantly reduce the load on the rest of the >system. Many modern full-featured UARTs have additional features like >swapping pin polarity (great for when people wire up RS-485 buses >incorrectly) or Rx/Tx pins, IrDA support, Smartcard support, Manchester >encoding and other things that could reasonably also be done in hardware >outside the UART.
And of course there are different balances that can be achieved between >features and power usage, and die space.
Usually most UARTs are usable for most purposes, but some are definitely >more convenient and better suited than others for offloading work.
Beyond that, you're correct that many modern SoCs have embedded
microcontrollers capable of real-time response; yay. Using one
just to avoid flow control over a serial protocol seems like
going to extremes to avoid a simple thing. As I mentioned, the
DW part even does CTS/RTS HW flow control automatically, without
software intervention.
I would not pick a UART to /avoid/ hardware flow control support - but
it is not a feature I have seen as useful since the days of dial-up
modems. XON/XOFF style of software flow control is completely absent
from anything I have been involved in. Of course there this software >synchronisation and control, but it is at a higher level.
On 25/06/2026 20:29, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
term% uname -a
Embedded ARM systems outship embedded x86 systems by a factor of 1000 or >>>>> more (from my attempts at googling - noting that you don't get real, >>>>> concrete figures without paying real, concrete money to marketing and >>>>> analysis companies). There are also devices where the core is neither >>>>> ARM nor x86. None of these, as a rule, have 16550's - they have much >>>>> better UARTs. (For small microcontrollers, "better" can mean smaller >>>>> and lower power, rather than necessarily additional useful features.) >>>>
OpenBSD rv64.local 7.9 GENERIC.MP#5 riscv64
term% dmesg | grep 16550
com0 at simplebus0: dw16550
term%
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
The dw16550 is synopsys (DW_apb_uart) optimized for the ARM
APB bus. It's modeled on the 16550 for backward compatability
yet includes additional features from 16650 and 16750 designs
using MMIO registers rather than the x86 I/O space registers.
It seems to be popular in some DSUs (e.g. Marvell Armada).
<snip> (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling
rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
There are various techniques to moderate the interrupt frequency
at high packet arrival rates. Usually based on a packet-count + timer; the >> interrupt fires after the specified number of packets has arrived
or the timer has expired.
Basically, a FIFO at the packet level, in the same way that byte FIFOs
work for UARTs ? I am sure that is a very good idea, especially for the >higher speed interfaces. I don't see a problem with thousands of
interrupts a second for 1 Gbps networking, but I do not see it going so
well when scaling by a factor of 100 for 100 Gpbs! And for even higher >rates, I believe it is common to have various kinds of accelerators
tightly integrated with the network interface, further reducing the work
(or at least the latency challenges) for the host. But again, those are
not things I have done myself.
On 25/06/2026 13:56, Dan Cross wrote:
In article <111gm0p$2vhih$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 13:04, Dan Cross wrote:
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
[snip]Is it really that hard?
Agreed.
It's only the setup that is a pain because of legacy terminal support. >>>>
struct termios term;
memset(&term, 0, sizeof(term));
cfmakeraw(&term); // BSD extension
cfsetispeed(&term, B38400);
cfsetospeed(&term, B38400);
term.c_cflag |= CS8 | CREAD | CRTSCTS;
tcsetattr(fd, TCSANOW, &term)
It took a good deal more than that when I did it. But it is certainly
possible that my reference sources for the task were not the best
available. Note also that it's not just the number of lines of C code - >>> it's knowing what those lines are, what settings you need, which headers >>> to find the declarations, etc.
One presumes that you if you are using, say, the POSIX
interfaces, you'll have some idea of how to write code for POSIX
and have access to a reference. My system's man pages are
reasonable for the latter.
Sure. But not all references are created equal, and I am merely saying
that the references or examples that I used might not have been the
best, or were maybe outdated or overly complex.
[snip]
I guess I am used to microcontroller programming - things happen far >>>>> more directly and efficiently there. (Or I use Python, were the source >>>>> code is simple and easy, and you don't think about the layers in between >>>>> the code and the hardware!)
"Efficiently" with respect to what? One could argue that MCUs
waste a lot of CPU cycles because their software is usually
terribly unsophisticated. A blocking system calll like `poll`
allows the operating system to context switch to some other
runnable task while the poll is pending, without the complexity
of directly handling interrupts.
No, I don't think you can argue that at all - sophisticated software at
the OS level wastes as many cycles as sophisticated software at the
application level.
Again, I ask, "efficiently" with respect to what? Note what I
said: "One could argue that MCUs waste a lot of CPU cycles
because their software _is usually terribly unsophisticated_":
emphasis added.
Let me rephrase - I don't think you can /reasonably/ argue that, without
at a minimum some concrete examples of MCUs wasting lots of CPU cycles
due to terribly unsophisticated software for UART handling, and a >justification for thinking it is common practice. I suppose you could
say that sometimes microcontroller software works by polling UART
hardware status registers in busy-waiting loops, but it is not likely to
be common practice except in special circumstances.
If code on my microcontroller wants to sent data to the UART (i.e., put
it into the software FIFO that feeds the hardware FIFO), the call is
perhaps 30 cycles plus maybe 6 or 8 per byte sent. Entering a "wait for
end of received frame event" is maybe 50 cycles, and the time from the
UART detecting the idle time, triggering the event, and the resulting >context switch starting up the blocked task is perhaps 200 cycles.
Those are all rough guesses out of my head, I have not measured them.
How many cpu cycles does it take for a program on Linux to send out a
dozen bytes on a UART, or between the UART hardware detecting the
receive timeout to the polling process exiting the poll() call?
[snip]
The purpose of an operating system is to control hardware,
isolate software principles from one another, and provide useful
programming abstractions. Essentially what you're saying is
that you don't want or need that, for some kinds of programs.
There a range of possible OS types, with kernels ranging from micro to >monolithic, widely different ideas of how much separation different
tasks need, and how much hardware control is done in the OS or in other >code. It is certainly the case that the features I want from an RTOS on
a microcontroller differ significantly from what I want in a general
purpose OS on a PC or other "big" system.
That's fine. But to extrapolate from that to, "and this
category of software is more efficient", as an absolute
statement, is what I take exception to: there's too much
disconfirming evidence to the contrary. Perhaps not in the
programs you personally write, but I took your statement was
general and not restricted to only those programs.
To be clear - when comparing efficiency, you have to know when you are >comparing apples to apples, and apples to oranges. My point is that for >many tasks, microcontrollers are more efficient but it is an apples to >oranges comparison in the details since the big OS has many other
important considerations.
Directly handling interrupts in a microcontroller is not particularly
complex - it's daily work for microcontroller developers.
Yes, because if your needs are not as general as those demanded
by general purposes operating systems on general purpose CPUs,
it can be made reasonably simple.
Exactly.
Microcontroller code will typically be much more focused and specialised.
As I mentioned, most (not
all) programs that target microcontrollers are not terribly
sophisticated, and have very modest requirements in this regard.
I am still not sure what you are saying here. It sounds a bit like you
have been saying the code is not sophisticated and therefore inefficient
and wasteful of cycles, when it is often the case that code is not very >sophisticated because it can be done simply and efficiently.
And we too know how to have blocking calls and multiple threads.
...and there are embedded OSes that have system calls and
privileged modes that restrict access to the hardware, too. :-}
Yes, there are. Again, I have used some of these at times.
In article <111jnmp$3tni8$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 12:47, Dan Cross wrote:Again, not something I was commenting on. Low(er) volume !=
[snip]
obsolete.
OK. I have already accepted that "obsolete" was an exaggeration. More
appropriate would be "not suitable for new designs".
Something approximately 16550-shaped will be in essentially
every new x86 SoC, because there's basically no incentive to
change: modern variants support DMA, speeds in the MBAUD, are
not tied to x86 programmed IO, and are fine for consoles,
communication between disparate IPs on a board, and so on.
I get that you don't think this series is suitable for embedded
use, and that's fine: don't use it if you you don't want to in microcontroller applications. But you're using your experience
in that domain to extrapolate and make a value judgement that
doesn't follow in a different domain.
The DW APB from Synopsis is common and I mentioned it at least
twice before Scott did, but you don't seem at all familiar with
it; it's pretty common.
[snip]
I just checked and it looks like ST ships PL011's in a bunch of
Cortex-M class parts.
Have you a reference for those?
[snip]
Actually, I think I was just wrong; the device I was thinking of
that used the PL011 off the shelf from ST was the ARM926 based
chip you mentioned: it's old, and they don't have them in their
Cortex-M offerings.
The RPi2040 and Zynq boards seem to have PL011s, but are much
lower volume.
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
That is from a JH7110 SoC in a StarFive VisionFive2 SBC. I use
those things for little utility machines around the house (DHCP,
DNS, etc).
Ok, fair points. I conress I find it somewhat difficult to
follow your exact line of discussion becuase it jumps between seemingly-unrelated points.
But yes, really - you /can/ handle thousands of interrupts per second on
Linux systems if you want to.
Of course. But eventually, if you saturate the system enough,
something has to give. That's when data in flight can get lost.
I've happily passed packets through Linux
systems at high speeds, without failures. My current system has a
microcontroller connected to a Linux SOM. My focus is on the
microcontroller software, but amongst other things I have Python code on
the PC sending UDP telegrams via the SOM (with a USB to Ethernet dongle)
to the microcontroller. I run about 2,000+ transactions a second,
without failures - where a transaction means the Linux SOM getting a
packet in, routing it out to the microcontroller, getting a reply back,
and routing that towards the PC. In the background, the SOM is
continuously bzipping and bunzipping a big file, just to have it working
on something. How many interrupts per second do you think that is?
No idea. About eight years ago, on a 192 Xeon core system, with
256GB of RAM and a 200Gbps NIC plus about 16TB of NVMe, I
regularly saw ~250k interrupts/sec across the fabric in the
steady-state, bursting up to a million or so.
Of course there are other patterns of interrupts that are more stressful
than the ones I have there. But then, I am running just a single core
SoC here, and the speed bottlenecks are mostly in the Python test code.
And I have done nothing towards improving the latencies or anything else
- this is a bog standard Debian ARM installation.
Perhaps that doesn't matter for your use cases, and you've never
needed it; but don't extrapolate to other use cases you have no
experience with.
I have worked on systems where we have locked interrupts and programs to
particular cores (of a 4 core SoC) to minimise jitter, with real-time
extensions in the kernel. Admittedly there were not many packets
handled in and out every millisecond, but the millisecond tick needed to
be within about 1% jitter.
So you're optimizing for latency, not throughput. Ok.
Of course there are vast combinations of hardware and requirements that
I have /not/ worked with. But I have seen enough to know that you can
do a great deal with Linux even without careful tuning - and even more
with tuning. Thousands of interrupts per second is peanuts to a modern
Linux system - big or small. Tens or hundreds of thousands of
interrupts per second - then you are pushing it, and will want to
re-think things a bit. (My understanding is that for very fast network
cards on big systems, you dedicate a core to the task and using polling
rather than interrupts to avoid context switches. But that is
definitely outside my experience.)
And certainly it is harder to do high frequency operations on Linux, and
on microprocessors, than on microcontrollers. Context switches are
massively more demanding, and you have little details like "security"
that are a different world on a multi-user system than on a
microcontroller. On one 500 MHz microcontroller I did some testing with
an RTOS doing round-robin context switches at 1 MHz, taking about 10% of
the processor capacity. I don't think you'd get far with a jiffy rate
of 1 MHz on any Linux system, big or small. And I have also had a
system where I did bit-banging of a 115200 baud UART with 4x
oversampling. That's 460,800 timer interrupts per second - on a
microcontroller running with a 18.432 MHz clock. 40 clocks per
interrupt, and time to spare for the rest of the application.
That, frankly, seems kind of hard to believe: the math just does
not add up, even assuming no wait states for access to e.g.
SRAM and single-cycle memory access times, with an instruction
dispatched per cycle; did you just, like, NEVER touch memory or
more than 2 or 3 registers in that path? Was the internal CPU
frequency 18MHz, or was that a reference oscillator?
I think the DW part I mentioned does, basically, all of those
thngs. I don't know about swapping Rx/Tx pins; I suspect that'd
be a function of the pin mux on the parts I'm most familiar
with.
And of course there are different balances that can be achieved between
features and power usage, and die space.
Usually most UARTs are usable for most purposes, but some are definitely
more convenient and better suited than others for offloading work.
Beyond that, you're correct that many modern SoCs have embedded
microcontrollers capable of real-time response; yay. Using one
just to avoid flow control over a serial protocol seems like
going to extremes to avoid a simple thing. As I mentioned, the
DW part even does CTS/RTS HW flow control automatically, without
software intervention.
I would not pick a UART to /avoid/ hardware flow control support - but
it is not a feature I have seen as useful since the days of dial-up
modems. XON/XOFF style of software flow control is completely absent
from anything I have been involved in. Of course there this software
synchronisation and control, but it is at a higher level.
Correction: it's not a feature that is usefulf or _your use
cases_. Again, I urge caution in making assumptions about other
use cases based on that.
In article <111jnmp$3tni8$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 12:47, Dan Cross wrote:Again, not something I was commenting on. Low(er) volume !=
[snip]
obsolete.
OK. I have already accepted that "obsolete" was an exaggeration.
More appropriate would be "not suitable for new designs".
Something approximately 16550-shaped will be in essentially
every new x86 SoC, because there's basically no incentive to
change: modern variants support DMA, speeds in the MBAUD, are
not tied to x86 programmed IO, and are fine for consoles,
communication between disparate IPs on a board, and so on.
In article <111jnmp$3tni8$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
I think the DW part I mentioned does, basically, all of those
thngs. I don't know about swapping Rx/Tx pins; I suspect that'd
be a function of the pin mux on the parts I'm most familiar
with.
Michael S <already5chosen@yahoo.com> wrote:
[ ... ][...]
About 25 years ago I wanted to synchronize my computer's clock to
the NIST Automated Computer Time Service [1] over a dialup modem.
The computer was an alphalinux with a 21164 if I remember correctly.
One core, but fast for the time.
NIST sends a ~50 character timestamp string, followed after a short pause
by a "*" on-time-marker. Reading the string one char at a time in a
tight loop didn't work, it dropped characters. Just saying.
The right way, in pseudocode:
[...]
[1] https://www.nist.gov/pml/time-and-frequency-division/time-distribution/automated-computer-time-service-acts
Don't know if NIST still operates the service. I hope so, there are
many places left with no Internet access.
In article <111jvkg$168d$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 25/06/2026 13:56, Dan Cross wrote:
In article <111gm0p$2vhih$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 13:04, Dan Cross wrote:
In article <111elok$2g1qh$2@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
[snip]
Let me rephrase - I don't think you can /reasonably/ argue that, without
at a minimum some concrete examples of MCUs wasting lots of CPU cycles
due to terribly unsophisticated software for UART handling, and a
justification for thinking it is common practice. I suppose you could
say that sometimes microcontroller software works by polling UART
hardware status registers in busy-waiting loops, but it is not likely to
be common practice except in special circumstances.
I'll wager a month's salary that the _vast_ bulk of MCU software
sits in a tight loop polling one or two bits in a couple of
registers. Sophisticated context handling, thread switching
(a lot of 8-bit MCUs just don't have enough memory available for
multiple stacks, let alone thread save areas), or even
interrupts are _probably_ pretty rare.
If code on my microcontroller wants to sent data to the UART (i.e., put
it into the software FIFO that feeds the hardware FIFO), the call is
perhaps 30 cycles plus maybe 6 or 8 per byte sent. Entering a "wait for
end of received frame event" is maybe 50 cycles, and the time from the
UART detecting the idle time, triggering the event, and the resulting
context switch starting up the blocked task is perhaps 200 cycles.
Those are all rough guesses out of my head, I have not measured them.
How many cpu cycles does it take for a program on Linux to send out a
dozen bytes on a UART, or between the UART hardware detecting the
receive timeout to the polling process exiting the poll() call?
That's an apples/oranges comparison.
What you really want to
ask is, how much time does it take to enqueue data into the
outbound ring buffer for a particular device, and how many
cycles does it take to fill the output FIFO from the ring when
space becomes available? Both of those costs _can_ be very low.
What is the cost of busy-waiting? It's hard to say.
If you only have a small handful of tasks, and everything is in
the same address space, then sure, picking a different thread to
run and doing the coroutine jump dance to resume it isn't that
hard.
Distance between timing out (say) a poll and a user program
exiting a system call is difficult to measure, since a polled
event happening doesn't mean that the system call automatically
returns; it means that the task that invoked the system call is
unblocked gets marked runnable; when it actually runs again
depends on a lot of factors (load vs available resources;
scheduling latency; time quantums assigned to currently running
tasks; etc). Most Unix/Linux-style schedulers are not real
time schedulers; so we freqntly just say, "eventually."
There's a whole branch of systems research devoted to doing this
as efficiently as possible.
[snip]
The purpose of an operating system is to control hardware,
isolate software principles from one another, and provide useful
programming abstractions. Essentially what you're saying is
that you don't want or need that, for some kinds of programs.
There a range of possible OS types, with kernels ranging from micro to
monolithic, widely different ideas of how much separation different
tasks need, and how much hardware control is done in the OS or in other
code. It is certainly the case that the features I want from an RTOS on
a microcontroller differ significantly from what I want in a general
purpose OS on a PC or other "big" system.
That's fine. But to extrapolate from that to, "and this
category of software is more efficient", as an absolute
statement, is what I take exception to: there's too much
disconfirming evidence to the contrary. Perhaps not in the
programs you personally write, but I took your statement was
general and not restricted to only those programs.
To be clear - when comparing efficiency, you have to know when you are
comparing apples to apples, and apples to oranges. My point is that for
many tasks, microcontrollers are more efficient but it is an apples to
oranges comparison in the details since the big OS has many other
important considerations.
That's kind of my point. The statement you made that I
responded to was that microcontroller software is "more
efficient" than what a general purpose OS does. It is more
nuanced than that, as it so often is: this is one reason I
dislike categorical statements of that nature.
Directly handling interrupts in a microcontroller is not particularly
complex - it's daily work for microcontroller developers.
Yes, because if your needs are not as general as those demanded
by general purposes operating systems on general purpose CPUs,
it can be made reasonably simple.
Exactly.
Microcontroller code will typically be much more focused and specialised.
Which doesn't necessarily mean more efficient. That was my
point.
As I mentioned, most (not
all) programs that target microcontrollers are not terribly
sophisticated, and have very modest requirements in this regard.
I am still not sure what you are saying here. It sounds a bit like you
have been saying the code is not sophisticated and therefore inefficient
and wasteful of cycles, when it is often the case that code is not very
sophisticated because it can be done simply and efficiently.
What I am saying is that words have meaning, and if you're going
to make an absolute statement about the relative efficiency of
one category of system versus another, you need to qualify what
you mean.
And we too know how to have blocking calls and multiple threads.
...and there are embedded OSes that have system calls and
privileged modes that restrict access to the hardware, too. :-}
Yes, there are. Again, I have used some of these at times.
The salient characteristic is that they share many of the same
properties of OSes on larger systems: MPUs might divide the
available address space into discrete regions, and so context
switching now involves memory-management hardware, where perhaps
it did not before. The point is that, even within "embedded
systems" there's too much variability to make absolute
statements. In general, I advice refraining from such for
precisely that reason.
[snip]
[snip]
I just checked and it looks like ST ships PL011's in a bunch of
Cortex-M class parts.
Have you a reference for those?
[snip]
Actually, I think I was just wrong; the device I was thinking of
that used the PL011 off the shelf from ST was the ARM926 based
chip you mentioned: it's old, and they don't have them in their
Cortex-M offerings.
OK. Those were older chips - in the earlier days of ARM processor SoCs >(though ST was a little later than many others), designs from the likes
of NXP and ST were based more on complete packages or reference designs
from ARM. The types of IP licenses these manufacturers have with ARM
have varied as they moved from making just a few ARM devices along with
all their other chips, towards having ARM processor and microcontroller >cores across a solid proportion of their portfolios. I expect they
started with whatever was easiest for other ARM users (thus the PL011),
and now integrate a lot more of their own peripherals in their chips. It
is also not uncommon that big manufacturers buy smaller manufacturers,
and so their early devices have whatever the small manufacturers used -
that will be off-the-shelf peripherals. Then later on, they do more >integration and use their own peripherals (saving them money). I don't
know the history of ST's ARM processor SoCs at all - despite being one
of the biggest in the ARM microcontroller world, they are relative
newcomers to the processor / embedded Linux side of things.
The RPi2040 and Zynq boards seem to have PL011s, but are much
lower volume.
That is perhaps slightly unexpected (for me) - both come from companies
that can happily make their own UART implementations to avoid additional >royalties to ARM, and money is always the main motivator. But maybe
they don't pay much, or maybe they make their own PL011-compatible UARTs
- ARM license terms are rarely public knowledge!
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
That is from a JH7110 SoC in a StarFive VisionFive2 SBC. I use
those things for little utility machines around the house (DHCP,
DNS, etc).
I think it's a good thing if there are more Risc-V devices around - ARM
is too dominant in many areas, and while standardisation on common
platforms is convenient, competition is good too.
How does this board compare to the ubiquitous Raspberry Pi's for such
uses? Neither DHCP nor DNS are particularly challenging applications, >unless you have a huge network, but your "etc." might cover other things.
[snip]
No idea. About eight years ago, on a 192 Xeon core system, with
256GB of RAM and a 200Gbps NIC plus about 16TB of NVMe, I
regularly saw ~250k interrupts/sec across the fabric in the
steady-state, bursting up to a million or so.
Perhaps we can conclude that Linux systems can handle lots of
interrupts, but too many become inefficient and have a risk of losing
some. Careful system tuning and consideration of the pattern of
interrupts lets you handle more without losses, but smarter hardware the >reduces the interrupt rate is essential at some point. And attempts at >putting figures on things is going to be too vague or require far more >detail of the hardware and applications than appropriate here.
[snip]
That, frankly, seems kind of hard to believe: the math just does
not add up, even assuming no wait states for access to e.g.
SRAM and single-cycle memory access times, with an instruction
dispatched per cycle; did you just, like, NEVER touch memory or
more than 2 or 3 registers in that path? Was the internal CPU
frequency 18MHz, or was that a reference oscillator?
No, the chip ran at 18.432 MHz - it was an 8-bit AVR microcontroller.
Most instructions are single cycle, except for branches (mostly 1 or 2 >cycles), call / return, and load/store to memory (2 cycles). That >application was all in assembly, and I split the cpu's 32 registers
between ones used in the software UART timer interrupt, and ones used in
the main code. Thus no cycles were needed for stacking or restoring >registers on interrupts, or other context switch stuff other than the PC
and flag registers.
It would, of course, have made more sense to have had a different >microcontroller with an additional UART, but sometimes you have to make >things work with the board you have. (And it was fun :-) )
On Sat, 27 Jun 2026 01:52:24 -0000 (UTC)
cross@spitfire.i.gajendra.net (Dan Cross) wrote:
In article <111jnmp$3tni8$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 25/06/2026 13:29, Dan Cross wrote:
In article <111gkgm$2vhih$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 24/06/2026 12:47, Dan Cross wrote:Again, not something I was commenting on. Low(er) volume !=
[snip]
obsolete.
OK. I have already accepted that "obsolete" was an exaggeration.
More appropriate would be "not suitable for new designs".
Something approximately 16550-shaped will be in essentially
every new x86 SoC, because there's basically no incentive to
change: modern variants support DMA, speeds in the MBAUD, are
not tied to x86 programmed IO, and are fine for consoles,
communication between disparate IPs on a board, and so on.
And why do you call such thing "16550-shaped" ?
What exactly is left from 16550?
In article <111p2a1$34arg$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
[snip]
[snip]
I just checked and it looks like ST ships PL011's in a bunch of
Cortex-M class parts.
Have you a reference for those?
[snip]
Actually, I think I was just wrong; the device I was thinking of
that used the PL011 off the shelf from ST was the ARM926 based
chip you mentioned: it's old, and they don't have them in their
Cortex-M offerings.
OK. Those were older chips - in the earlier days of ARM processor SoCs
(though ST was a little later than many others), designs from the likes
of NXP and ST were based more on complete packages or reference designs >>from ARM. The types of IP licenses these manufacturers have with ARM
have varied as they moved from making just a few ARM devices along with
all their other chips, towards having ARM processor and microcontroller
cores across a solid proportion of their portfolios. I expect they
started with whatever was easiest for other ARM users (thus the PL011),
and now integrate a lot more of their own peripherals in their chips. It
is also not uncommon that big manufacturers buy smaller manufacturers,
and so their early devices have whatever the small manufacturers used -
that will be off-the-shelf peripherals. Then later on, they do more
integration and use their own peripherals (saving them money). I don't
know the history of ST's ARM processor SoCs at all - despite being one
of the biggest in the ARM microcontroller world, they are relative
newcomers to the processor / embedded Linux side of things.
My guess is that for the embedded market, they favor cost saving
compounded by volume; at scale, a 5c difference in the cost of a microcontroller can add up. For application-profile cores, it's
less of a consideration on the margins, so they favor
standardization to leverage network effects around software
ecosystems.
The RPi2040 and Zynq boards seem to have PL011s, but are much
lower volume.
That is perhaps slightly unexpected (for me) - both come from companies
that can happily make their own UART implementations to avoid additional
royalties to ARM, and money is always the main motivator. But maybe
they don't pay much, or maybe they make their own PL011-compatible UARTs
- ARM license terms are rarely public knowledge!
For RPi, this was one of their first in-house designs, versus
using one of Broadcom's offerings, wasn't it? Perhaps they went
with off-the-shelf IP for the UART to minimize risk. For Zynq,
I suspect the cost of the FPGA dwarfs whatever savings they'd
get from their own UART, so they favor software compatibility.
That is very interesting, and somewhat unexpected. Thanks for the
example. Where is this riscv core from?
That is from a JH7110 SoC in a StarFive VisionFive2 SBC. I use
those things for little utility machines around the house (DHCP,
DNS, etc).
I think it's a good thing if there are more Risc-V devices around - ARM
is too dominant in many areas, and while standardisation on common
platforms is convenient, competition is good too.
How does this board compare to the ubiquitous Raspberry Pi's for such
uses? Neither DHCP nor DNS are particularly challenging applications,
unless you have a huge network, but your "etc." might cover other things.
I agree, and I'm happy to have RISC-V boards to work with.
However, compared to an RPi, it's not fast; maybe comparable to
an RPi2 or RPi3. However, it has native NVMe and an M.2 slot at
Gen2x4 and a real Ethernet PHY (not a USB bridge), that can
eliminate some of the IO slowness of older RPi hardare.
In terms of competative application cores available at scale,
the RV64 ecosystem has a lot of work to do.
[snip]
No idea. About eight years ago, on a 192 Xeon core system, with
256GB of RAM and a 200Gbps NIC plus about 16TB of NVMe, I
regularly saw ~250k interrupts/sec across the fabric in the
steady-state, bursting up to a million or so.
Perhaps we can conclude that Linux systems can handle lots of
interrupts, but too many become inefficient and have a risk of losing
some. Careful system tuning and consideration of the pattern of
interrupts lets you handle more without losses, but smarter hardware the
reduces the interrupt rate is essential at some point. And attempts at
putting figures on things is going to be too vague or require far more
detail of the hardware and applications than appropriate here.
Agreed.
[snip]
That, frankly, seems kind of hard to believe: the math just does
not add up, even assuming no wait states for access to e.g.
SRAM and single-cycle memory access times, with an instruction
dispatched per cycle; did you just, like, NEVER touch memory or
more than 2 or 3 registers in that path? Was the internal CPU
frequency 18MHz, or was that a reference oscillator?
No, the chip ran at 18.432 MHz - it was an 8-bit AVR microcontroller.
Most instructions are single cycle, except for branches (mostly 1 or 2
cycles), call / return, and load/store to memory (2 cycles). That
application was all in assembly, and I split the cpu's 32 registers
between ones used in the software UART timer interrupt, and ones used in
the main code. Thus no cycles were needed for stacking or restoring
registers on interrupts, or other context switch stuff other than the PC
and flag registers.
It would, of course, have made more sense to have had a different
microcontroller with an additional UART, but sometimes you have to make
things work with the board you have. (And it was fun :-) )
Huh. Well, ok; sounds challenging!
On 27/06/2026 04:22, Dan Cross wrote:
[snip]
That's fair enough (and I've tried to be a bit more nuanced in this
reply). Equally, however, you made some pretty categorical claims about >microcontroller software being "terribly unsophisticated" and "wasting a
lot of CPU cycles". But I think we have written enough on these things
- unless we can find a way to bring it back to C!
One thing you might not be aware of is the difference between what is >generally termed a "Memory Protection Unit" (MPU) and a "Memory
Management Unit" (MMU). With the proviso that the terms are not
strictly defined and the there can be exceptions in both hardware and >software usage, an MMU generally deals with translations of virtual >addresses to physical addresses as well as controlling accesses (at
either the virtual or physical address level). An MPU normally does not
do any translation - it is for access control and determining address
space characteristics like cacheability. In an RTOS on a
microcontroller, the MPU is typically configured once at startup and not >changed thereafter - including during context switches. There can be a >distinction between some kind of "privileged", "supervisor" or "system"
mode and "user", "problem" or "task" mode (terminology varies >significantly), and also between "secure" and "non-secure" modes. But
the MPU, together with any other security features, bus access blocks,
etc., will normally have a single setup to say what memory and
peripherals are accessible by code running in each mode. The MPU does
not need changed between threads (with the exception of sometimes
changing one window used for catching stack overflows in some setups),
and does not have the kind of context switch overhead required between >processes in a big system with virtual memory and security and
protection between tasks.
Sorry for the delayed response; we were traveling with the
holiday. I just wanted to touch on a few points.
In article <111rjtr$3ofre$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 27/06/2026 04:22, Dan Cross wrote:
[snip]
That's fair enough (and I've tried to be a bit more nuanced in this >>reply). Equally, however, you made some pretty categorical claims about >>microcontroller software being "terribly unsophisticated" and "wasting a >>lot of CPU cycles". But I think we have written enough on these things
- unless we can find a way to bring it back to C!
Fair. I thought I had tried to qualify it to say much, not all,
however.
One thing you might not be aware of is the difference between what is >>generally termed a "Memory Protection Unit" (MPU) and a "Memory
Management Unit" (MMU). With the proviso that the terms are not
strictly defined and the there can be exceptions in both hardware and >>software usage, an MMU generally deals with translations of virtual >>addresses to physical addresses as well as controlling accesses (at
either the virtual or physical address level). An MPU normally does not >>do any translation - it is for access control and determining address >>space characteristics like cacheability. In an RTOS on a
microcontroller, the MPU is typically configured once at startup and not >>changed thereafter - including during context switches. There can be a >>distinction between some kind of "privileged", "supervisor" or "system" >>mode and "user", "problem" or "task" mode (terminology varies >>significantly), and also between "secure" and "non-secure" modes. But
the MPU, together with any other security features, bus access blocks, >>etc., will normally have a single setup to say what memory and
peripherals are accessible by code running in each mode. The MPU does
not need changed between threads (with the exception of sometimes
changing one window used for catching stack overflows in some setups),
and does not have the kind of context switch overhead required between >>processes in a big system with virtual memory and security and
protection between tasks.
No, I'm aware that MPUs don't generally provide relocation
facilities, but they _do_ often provide more than one region;
the Cortex-M7 parts we use for the service processor embedded in
our machines supports (if memory serves) 16 that we divide
between the various tasks we run on the microcontroller. In our
embedded OS (Hubris) we manually permit each task's region (and
depermit others) on context switch.
Sorry for the delayed response; we were traveling with the
holiday. I just wanted to touch on a few points.
In article <111rjtr$3ofre$1@dont-email.me>,
David Brown <david.brown@hesbynett.no> wrote:
On 27/06/2026 04:22, Dan Cross wrote:
[snip]
That's fair enough (and I've tried to be a bit more nuanced in this
reply). Equally, however, you made some pretty categorical claims about
microcontroller software being "terribly unsophisticated" and "wasting a
lot of CPU cycles". But I think we have written enough on these things
- unless we can find a way to bring it back to C!
Fair. I thought I had tried to qualify it to say much, not all,
however.
One thing you might not be aware of is the difference between what is
generally termed a "Memory Protection Unit" (MPU) and a "Memory
Management Unit" (MMU). With the proviso that the terms are not
strictly defined and the there can be exceptions in both hardware and
software usage, an MMU generally deals with translations of virtual
addresses to physical addresses as well as controlling accesses (at
either the virtual or physical address level). An MPU normally does not
do any translation - it is for access control and determining address
space characteristics like cacheability. In an RTOS on a
microcontroller, the MPU is typically configured once at startup and not
changed thereafter - including during context switches. There can be a
distinction between some kind of "privileged", "supervisor" or "system"
mode and "user", "problem" or "task" mode (terminology varies
significantly), and also between "secure" and "non-secure" modes. But
the MPU, together with any other security features, bus access blocks,
etc., will normally have a single setup to say what memory and
peripherals are accessible by code running in each mode. The MPU does
not need changed between threads (with the exception of sometimes
changing one window used for catching stack overflows in some setups),
and does not have the kind of context switch overhead required between
processes in a big system with virtual memory and security and
protection between tasks.
No, I'm aware that MPUs don't generally provide relocation
facilities, but they _do_ often provide more than one region;
the Cortex-M7 parts we use for the service processor embedded in
our machines supports (if memory serves) 16 that we divide
between the various tasks we run on the microcontroller. In our
embedded OS (Hubris) we manually permit each task's region (and
depermit others) on context switch.
| Sysop: | Tetrazocine |
|---|---|
| Location: | Melbourne, VIC, Australia |
| Users: | 12 |
| Nodes: | 8 (0 / 8) |
| Uptime: | 198:53:36 |
| Calls: | 220 |
| Files: | 21,513 |
| Messages: | 83,335 |