[ Content | Sidebar ]

Archives for programming

SIGPIPE and how to ignore it

September 23rd, 2020

I recently found myself trying to port a program that uses Boost Asio to run on OpenBSD. Everything compiled OK but while running it would occasionally exit with an unhandled SIGPIPE signal. This doesn’t happen on Linux. What’s going on here?

SIGPIPE is a synchronous signal that’s sent to a process (thread in POSIX.1-2004) which attempts to write data to a socket or pipe that has been closed by the reading end. Importantly it’s not an asynchronous signal that notifies you when the reading end has been closed: it’s delivered only when you attempt to write data. In fact it’s generated precisely when the system call (write(2), sendmsg(2), etc.) would fail with EPIPE and doesn’t give any additional information.

So what’s the point then? The default action for SIGPIPE is to terminate the process without a core dump (just like SIGINT or SIGTERM). This simplifies error handling in programs that are meant to run as part of a shell pipeline: reading input, transforming it, and then writing it to another process. SIGPIPE allows the program to skip error handling and blindly write data until it’s killed.

For programs that handle write errors it doesn’t seem to be useful and is best avoided. But unfortunately there are several different ways to do that.

Ignore the signal globally

This is the easiest if you are in complete control of the program (i.e. not writing a library). Just set the signal to SIG_IGN and forget about it.

signal(SIGPIPE, SIG_IGN);

Use MSG_NOSIGNAL

If you are writing to a socket, and not an actual pipe, pass the MSG_NOSIGNAL flag to send(2) or sendmsg(2). This has been in Linux for ages and was standardised in POSIX.1-2008 so it’s available almost anywhere.

Set SO_NOSIGPIPE socket option

This is a bit niche as it only exists on FreeBSD and OS X. Use setsockopt(2) to set this option on a socket and all subsequent send(2) calls will behave as if MSG_NOSIGNAL was set.

int on = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on))

This seems to be of limited utility as calling write(2) on the socket will still generate SIGPIPE. The only use I can think of is if you need to pass the socket to a library or some other code you don’t control.

Temporarily mask the signal on the current thread

The most general solution, for when you are not in full control of the program’s signal handling and want to write data to an actual pipe or use write(2) on a socket, is to first mask the signal for the current thread with pthread_sigmask(3), write the data, drain any pending signal with sigtimedwait(2) and a zero timeout, and then finally unmask SIGPIPE. This technique is described in more detail here. Note that some systems such as OpenBSD do not have sigtimedwait(2) in which case you need to use sigpending(2) to check for pending signals and then call the blocking sigwait(2).

Anyway back to the original problem. Asio hides SIGPIPE from the programmer by either setting the SO_NOSIGPIPE socket option on systems that support it, or on Linux by passing MSG_NOSIGNAL to sendmsg(2). None of these apply to OpenBSD which is why we get the SIGPIPE. I submitted a pull request to pass MSG_NOSIGNAL on OpenBSD as well. But I don’t know when or if that will be merged so I’m also trying to get the same fix added to the ports tree.

UPDATE: a patch is now in the ports tree.

Making Emacs GUD Usable

June 9th, 2019

Emacs provides a wrapper for various debuggers including GDB called the Grand Unified Debugger (GUD). I’ve tried it in the past but always run into lots of minor annoyances with the UI so I just use command line GDB instead. But recently I’ve being trying to adopt a more “Emacs native” workflow, including using EShell instead of a separate terminal window for Bash, Magit instead of command line git, ERC for IRC, etc. So let’s see if we can fix these GUD problems…

Basic configuration

(setq gdb-many-windows t
      gdb-use-separate-io-buffer t)

The default mode of GUD just creates a single window with the the normal GDB terminal. This doesn’t seem to offer much over running GDB directly. The “many windows” mode splits the screen into six separate windows showing the current source file, locals/registers, output, etc.

Source file opens in the wrong window

By default if you jump to a source file from e.g. the stack trace window it will open on top of the command input window (labeled “2” below) rather than the source file window “1”.

This seems to be “normal” behaviour, and there are loads of threads on Stack Overflow complaining about it but with no conclusive solution. E.g. see here or here.

The problem here is that GUD makes all the popup windows “dedicated” except for the command window. When you jump to a file it opens in the first non-dedicated window, which sort-of makes sense. The function that sets up the windows is called gdb-setup-windows so we can use Emacs’ “advice” system to hook this function and run some extra code afterwards to make the command window dedicated:

(advice-add 'gdb-setup-windows :after
            (lambda () (set-window-dedicated-p (selected-window) t)))

This works because gdb-setup-windows always leaves the command window selected when it finishes.

Quitting messes up the window configuration

How do you quit anyway? I think the correct way is just to run quit in the command window. But no matter how you quit GUD always messes up whatever window configuration you had before you opened it.

We can fix that by saving the window layout when we run M-x gdb by storing the layout into a register in gud-mode-hook. The gud-sentinal function runs when some event occurs on the inferior gdb process. We can hook that to restore the window state when the process exits.

(defconst gud-window-register 123456)
 
(defun gud-quit ()
  (interactive)
  (gud-basic-call "quit"))
 
(add-hook 'gud-mode-hook
          (lambda ()
            (gud-tooltip-mode)
            (window-configuration-to-register gud-window-register)
            (local-set-key (kbd "C-q") 'gud-quit)))
 
(advice-add 'gud-sentinel :after
            (lambda (proc msg)
              (when (memq (process-status proc) '(signal exit))
                (jump-to-register gud-window-register)
                (bury-buffer))))

I’ve bound C-q to gud-quit which send the quit command to GDB to save typing.

Using ORC with LLVM’s C API

May 11th, 2017

I recently updated the JIT back-end of my VHDL simulator to use LLVM’s new ORC API which was added in version 3.9. It has a couple of advantages, the two important ones for me were re-introduction of lazy-JIT-ing of functions, and that it works on Windows. Both features that were lost moving from the legacy JIT API to the newer MCJIT one. ORC is actually built as a layer on top of MCJIT though.

Documentation seems to be pretty scarce. There’s some example code but it all uses the C++ API so I thought it might be useful to write some notes on how I use it with the C API. You simply need to include this header and then either link against the LLVM shared library or llvm-config --libs orcjit.

#include <llvm-c/OrcBindings.h>

Initialise the LLVM libraries and MCJIT back-end which ORC is built on:

LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMLinkInMCJIT();

Let’s assume you already have an LLVM bitcode module from somewhere else:

LLVMModuleRef module = ...;

Unlike the MCJIT API and the original LLVM JIT API you need a “target machine” reference to create the ORC object. This is probably the only non-obvious part but a bit of searching in the other headers finds some functions to do it:

char *def_triple = LLVMGetDefaultTargetTriple();   // E.g. "x86_64-linux-gnu"
char *error;
LLVMTargetRef target_ref;
if (LLVMGetTargetFromTriple(def_triple, &target_ref, &error)) {
   // Fatal error
}
 
if (!LLVMTargetHasJIT(target_ref)) {
   // Fatal error, cannot do JIT on this platform
}
 
LLVMTargetMachineRef tm_ref =
   LLVMCreateTargetMachine(target_ref, def_triple, "", "",
                           LLVMCodeGenLevelDefault,
                           LLVMRelocDefault,
                           LLVMCodeModelJITDefault);
assert(tm_ref);
LLVMDisposeMessage(def_triple);

The two empty string arguments to LLVMCreateTargetMachine are CPU and Features. I can’t work out what these are used for and everything works fine if you pass an empty string. On LLVM 4.0 you can pass NULL here but this crashes on 3.9.

I haven’t experimented with anything other the default relocation model, which seems to work everywhere I tried it, or the optimisation level.

Now we can actually create the ORC object:

LLVMOrcJITStackRef orc_ref = LLVMOrcCreateInstance(tm_ref);
LLVMOrcAddLazilyCompiledIR(orc_ref, module, orc_sym_resolver, NULL);

The only interesting argument is orc_sym_resolver. This is a pointer to callback ORC will use when it needs you to resolve a symbol.

static uint64_t orc_sym_resolver(const char *name, void *ctx)
{
   return (uint64_t)(uintptr_t)LLVMOrcGetSymbolAddress(orc_ref, name);
}

The function LLVMOrcGetSymbolAddress seems to do exactly what we want, but you could do some custom symbol lookup if required.

You can also use this function to trigger the lazy compilation and get a function pointer to the result. For example:

int (*main_fn)(void) = LLVMOrcGetSymbolAddress(orc_ref, "main");
int result = (*main_fn)();

Writes Your Makefiles For You

December 31st, 2013

I’ve been dogfooding my VHDL compiler for a project at work and now that it’s gotten to the point where it can simulate non-trivial designs, compile times are becoming significant. Especially when files use Xilinx primitives as the vcomponents library takes a while to load.

At the moment I’m re-analysing every source file for each change I make, so obviously an improvement would be to write a makefile and only re-analyse the files that have changed and those that depend on them (e.g. an architecture must be re-analysed if the corresponding entity changed). But figuring out and maintaining the dependencies by hand is tedious and error prone so I’ve written a makefile generator that recursively finds the dependencies for previously analysed or elaborated units in a library. Invoke it like this:

nvc --make my_top_level >Makefile

Then running make will do the minimum amount of work to rebuild all the out of date files. If the argument to --make is an elaborated design then two convenience targets run and wave will be added to run the simulation and run with waveform output respectively.

The code is fairly compact: only 400 or so lines of C.

This also turned out to be handy for solving a long-standing problem of not being able to bootstrap the standard and IEEE libraries with parallel make (make -j). Previously the dependencies in the automake input file were incomplete, but now these are generated automatically by a gen-deps target. The output (e.g. here) is then mangled with sed and committed into the git repository (this solves a chicken-and-egg problem where the gen-deps target can only be run in an already built tree).

Improved Waveform Output

October 27th, 2013

I’ve spent a lot of time recently improving the waveform output of my VHDL compiler / simulator. Previously only the simple VCD format was supported: this only allows Verilog-style 4-value logic types to be dumped so doesn’t map very well onto VHDL types. The implementation was also very inefficient resulting in a 3-4x slowdown in simulation speed.

After experimenting with LXT for a while, NVC now uses GtkWave’s FST format by default. With some help from GtkWave’s author it can now dump full 9-value logic as well as most common VHDL types (enumerations, strings, integers, etc.).

I’ve put some work into improving the performance of waveform output and now dumping every signal to a FST incurs around 30% overhead. The VCD dumper has also been rewritten giving around 90% overhead. This format should generally be avoided unless you do not have access to GtkWave.

The screen shot below shows some of the new features:

gtkwave

Automagic Debugging

July 8th, 2012

It’s kind of annoying to have to go back and run GDB after your program crashes. Here’s a signal handler I’ve been using which drops you into GDB straight away:

static void gdb_sighandler(int sig, siginfo_t *info)
{
   char exe[256];
   if (readlink("/proc/self/exe", exe, sizeof(exe)) < 0) {
      perror("readlink");
      exit(EXIT_FAILURE);
   }
 
   char pid[16];
   snprintf(pid, sizeof(pid), "%d", getpid());
 
   pid_t p = fork();
   if (p == 0) {
      execl("/usr/bin/gdb", "gdb", "-ex", "cont", 
            exe, pid, NULL);
      perror("execl");
      exit(EXIT_FAILURE);
   }
   else if (p < 0) {
      perror("fork");
      exit(EXIT_FAILURE);
   }
   else {
      // Allow a little time for GDB to start before 
      // dropping into the default signal handler
      sleep(1);
      signal(sig, SIG_DFL);
   }
}

This probably breaks all sorts of rules on what you shouldn’t do in a signal handler but hey, it was going to crash anyway. Resetting the handler to SIG_DFL at the end is important or you’ll end up stuck in a loop when you try to quit GDB. Install it for all the unpleasant signals like this:

struct sigaction sa;
sa.sa_sigaction = (void*)gdb_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
 
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);

It’s probably worth checking whether GDB is already running before you do this. On Linux you can check this by trying to ptrace yourself: if it succeeds then a debugger isn’t attached.

static int is_debugger_running(void)
{
   pid_t pid = fork();
   if (pid == -1) {
      perror("fork");
      exit(EXIT_FAILURE);
   }
   else if (pid == 0) {
      int ppid = getppid();
      if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0) {
         waitpid(ppid, NULL, 0);
         ptrace(PTRACE_CONT, NULL, NULL);
         ptrace(PTRACE_DETACH, getppid(), NULL, NULL);
         exit(0);
      }
      else
         exit(1);
   }
   else {
      int status;
      waitpid(pid, &status, 0);
      return WEXITSTATUS(status);
   }
}

Portable high resolution timestamps from stat

April 21st, 2012

A small nugget of information that might be useful to someone:

The standard timestamps in struct stat have type time_t which only gives a resolution of seconds which is less than required in many situations. Luckily most operating systems provide a higher resolution timestamp within struct stat but the field name differs among Linux, BSD, etc. On Linux you can get at this with st_mtim.tv_nsec and on BSD it is st_mtimespec.tv_nsec (this also works for OS X).

With autoconf you can use something like:

AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec])
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])

And then later you can pull the nanoseconds out of the timestamp with:

#if defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
   ns = st.st_mtimespec.tv_nsec;
#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
   ns = st.st_mtim.tv_nsec;
#else
   ns = 0;
#endif

This works the same way for atime and ctime as well as mtime. Make sure to handle the #else case as some systems (Cygwin?) don’t have this at all.

VHDL compiler improvements

April 15th, 2012

A while ago I posted about a VHDL compiler I’d started writing. Well I’ve been working on it a bit during the evenings and weekends and it’s acquired several new features. Probably the most significant is that it can now compile the standard IEEE std_logic_1164 and numeric_std packages as well the Synopsys std_logic_arith and std_logic_unsigned packages. If you clone the latest version from GitHub these will be built and installed for you automatically. Note that the original IEEE sources cannot be redistributed due to copyright restrictions so you’ll have to faff about downloading them from the IEEE standards website first – see lib/ieee/README for details.

NVC also now supports a wider range of concurrent statements, including selected and conditional assignments.

This means we can rewrite the counter example from before in a more normal way:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity counter is
    generic ( WIDTH : integer );
    port (
        clk   : in std_logic;
        reset : in std_logic;
        count : out unsigned(WIDTH - 1 downto 0) );
end entity;
 
architecture rtl of counter is
    signal count_r : unsigned(WIDTH - 1 downto 0);
begin
    count <= count_r;
 
    process (clk) is
    begin
        if rising_edge(clk) then
            if reset = '1' then
                count_r <= (others => '0');
            else
                count_r <= count_r + 1;
            end if;
        end if;            
    end process;
end architecture;

And similarly for the top-level test bench:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity counter_tb is end entity;
 
architecture test of counter_tb is
    constant WIDTH : integer := 16;
    signal clk     : std_logic := '0';
    signal reset   : std_logic := '1';
    signal count   : unsigned(WIDTH - 1 downto 0);
begin
    clk   <= not clk after 5 ns;
    reset <= '0' after 10 ns;
 
    uut: entity work.counter
        generic map ( WIDTH )
        port map ( clk, reset, count );    
end architecture;

Next we have to analyse and elaborate the design:

$ nvc -a counter.vhd
$ nvc -e counter_tb
/usr/lib/llvm-3.0/bin/llvm-ld -r -b /home/nick/nvc/build/work/_WORK.COUNTER_TB.final.bc /home/nick/nvc/build/work/_WORK.COUNTER_TB.elab.bc /home/nick/share/nvc/ieee/_IEEE.NUMERIC_STD-body.bc /home/nick/share/nvc/ieee/_IEEE.STD_LOGIC_1164-body.bc

The long llvm-ld line at the end is a new stage that links together the LLVM bitcode for the elaborated design with the bitcode for any referenced packages – the IEEE standard libraries in this case. This allows LLVM’s link time optimisation to optimise across package boundaries. For example, inlining trivial functions like rising_edge directly into the process.

$ nvc -r --stop-time=1ms --stats counter_tb
** Note: setup:28ms run:104ms maxrss:17872kB

LLVM JIT compilation accounts for most of the memory usage and 28ms setup time. However this overhead should be insignificant for any long-running simulation.

Just running the above simulation is fairly boring so I’ve also started adding a basic VCD dumper. This only works for a small set of data types but includes std_logic and std_logic_vector so should hopefully be quite useful in practice.

$ nvc -r --stop-time=100ns --vcd=out.vcd counter_tb

The output can then be opened in a VCD viewer such as GTKWave.

Note that writing out a VCD will slow the simulation considerably. In the future I’d like to be able to selectively dump signals and support other formats such as GHW or LXT2.

Writing a VHDL compiler

November 5th, 2011

I haven’t posted much about any of my projects for a some time. This is because I’ve spent the past few months squirrelling away on something new: a while ago I decided a good way to learn more about VHDL would be to write a parser/checker for it. I had a vague plan of using it to write a linting tool or indexer. I’ve also wanted to learn more about LLVM so I started hacking together a code generator on the back end of the linting tool that generated LLVM IR for sequential VHDL processes. After that I thought I might as well write a simulation kernel too and it snowballed into something approximating an embryonic VHDL compiler/simulator.

The tool is currently called “nvc” which might stand for “Nick’s VHDL Compiler” or perhaps “New VHDL Compiler”. You can get it from GitHub here: github.com/nickg/nvc. See the README file for instructions on how to build and run it.

The eventual goal is full IEEE 1076-1993 support, or at least as much as possible until I get bored. Currently its capabilities are very limited. In particular it doesn’t implement enough of VHDL to compile the IEEE std_logic_1164 package which makes it almost useless for any real-world designs. The following should give an example of what it can do at the moment though.

entity counter is
    port (
        clk   : in bit;
        count : out integer );
end entity;
 
architecture behav of counter is
begin
    process (clk) is
        variable count_var : integer := 0;
    begin
        if clk'event and clk = '1' then
            count_var := count_var + 1;
            count <= count_var;
        end if;
    end process;
end architecture;

This is a very simple behavioural model of a counter that increments on rising edges of clk. We can also add a top-level entity to generate the clock signal:

entity top is end entity;
 
architecture test of top is
    signal clk   : bit := '0';
    signal count : integer := 0;
begin
    clkgen: process is
    begin
        wait for 5 ns;
        clk <= not clk;
    end process;
 
    uut: entity work.counter
        port map (
            clk   => clk,
            count => count );
 
    process (count) is
    begin
        report integer'image(count);
    end process;
end architecture;

The final process will print the value of the counter every time it changes. You may normally have written the clkgen process with a concurrent assignment:

clk <= not clk after 5 ns;

Unfortunately processes and instantiations and the only sort of concurrent statements implemented in nvc at the moment. This is not as restrictive as it sounds: apart from generate statements all others can be trivially rewritten as processes. This is in fact how they are specified in the standard.

First we need to run the analysis step which parses the code into an internal format, performs type checking, and runs some simplification passes such as constant folding. With the above code in a single file counter.vhd we can run:

$ nvc -a counter.vhd
[gc: freed 425 trees; 297 allocated]

The work library now contains the serialised abstract syntax tree for each analysed design unit:

$ ls -lh work
total 24K
-rw-r--r-- 1 nick nick    8 Nov  5 13:37 _NVC_LIB
-rw-r--r-- 1 nick nick  682 Nov  5 13:37 WORK.COUNTER
-rw-r--r-- 1 nick nick 1.6K Nov  5 13:37 WORK.COUNTER-BEHAV
-rw-r--r-- 1 nick nick   33 Nov  5 13:37 WORK.TOP
-rw-r--r-- 1 nick nick 7.6K Nov  5 13:37 WORK.TOP-TEST

Next we run the elaboration step which builds the full design hierarchy starting from a top level entity. It also runs the LLVM IR code generation step to produce a bitcode file.

$ nvc -e top

(This step produces a large amount of debug output which should be ignored.) If you look inside the work library again you should see the generated LLVM bitcode and a serialised AST for the elaborated design – this is used for debugging later.

$ ls -lhtr work | tail -2
-rw-r--r-- 1 nick nick 8.2K Nov  5 13:39 WORK.TOP.elab
-rw-r--r-- 1 nick nick 1.3K Nov  5 13:39 _WORK.TOP.elab.bc

The elaboration step runs a number of simple LLVM optimisation passes over the bitcode before writing it out but you can run more if you like using the standard LLVM opt tool.

Now we can finally simulate the model! The simplest way to do this is in batch mode as follows:

$ nvc -r --stop-time=50ns top
0ms+0: Report Note: 0
5ns+2: Report Note: 1
15ns+2: Report Note: 2
25ns+2: Report Note: 3
35ns+2: Report Note: 4
45ns+2: Report Note: 5

Normally nvc will run until there are no more events scheduled but as the clkgen process will schedule events forever we have to specify an explicit stop time. The bitcode file is transparently converted into native machine code using LLVM’s JIT engine when the simulation is loaded.

Commercial simulators usually provide an interactive debugging environment as well as a batch mode and nvc tries to emulate this. Use the -c switch to the run command to enter interactive mode:

$ nvc -r -c top
%

This mode uses TCL for command processing, which is the de-facto standard for scripting in the EDA industry. If you have readline or libedit installed you’ll also get fancy line-editing capabilities. The features here are currently pretty limited but we can see the state of all the signals in the design:

% show signals
:top(test):clk                STD.STANDARD.BIT         '0'
:top(test):count              STD.STANDARD.INTEGER     0

Note that nvc has collapsed the ports in counter with the signals in top as they are identical: this might be confusing if you’re searching for a particular name. Now we can run the simulation and verify the signal values change:

% run 45 ns
% 0ms+0: Report Note: 0
5ns+2: Report Note: 1
15ns+2: Report Note: 2
25ns+2: Report Note: 3
35ns+2: Report Note: 4
45ns+2: Report Note: 5
 
% show signals
:top(test):clk                STD.STANDARD.BIT         '1'
:top(test):count              STD.STANDARD.INTEGER     5

Notice that the run command returns straight away and the print outs happen in the background: this is because the interactive mode forks off another process to run the simulation.

A legacy of the project’s origins as a linter, the error messages try to be more helpful than most VHDL compilers:

counter.vhd:33: no suitable overload for operator 
"+"(STD.STANDARD.BIT, universal integer)
            clk <= not (clk + 1);
                        ^^^^^^^

This is about the limit of what nvc can do at the moment. I’m not sure how far I’ll develop it but it’s been good fun hacking thus far. So obviously don’t start using it for real designs or reporting bugs just yet ;-).

Conky BBC weather

April 17th, 2011

I’ve written a Ruby script called bbc-weather.rb that parses the BBC weather RSS for a particular location and formats the data for conky. Here’s an example:

To use it insert the following in your .conkyrc:

${execpi 600 ruby /path/to/bbc-weather.rb 4197}

This will refresh every hour. Replace 4197 with the number of your local weather station. You can find this by looking at the BBC weather URL which is of the form weather/forecast/XXXX. You also need to define two colours for the script to use, in the options section before TEXT, like so:

color1 white
color2 grey

You might also need the following, as conky limits the about of text it will read from a sub-process:

text_buffer_size 2048

UPDATE: apparently this script no longer works with recent BBC Weather updates. Check out the comments for an improved version.