Skip to content

Instantly share code, notes, and snippets.

@ivarne
Last active January 4, 2016 08:39
Show Gist options
  • Save ivarne/8597002 to your computer and use it in GitHub Desktop.
Save ivarne/8597002 to your computer and use it in GitHub Desktop.

Dealing with errno in c-APIs in Julia

Lots of C APIs that you might want to call from julia uses a special thread local global integer errno to indicate errors because C only allows one return value and does not provide exceptions to indicate errors. Usually the function interface will define a special return value to indicate an error, and let set errno to a number that represents an index into an array of standard error messages. Some functions, like unix strtoul, do not have a special value to indicate error, but says it will change errno to an appropriate value if an error is encountered. This will require a cautious programmer to set errno = 0; before calling the function and check if it is different from 0 after calling the function.

Example usage in c

errno = 0;
arg = strtoul (buf, NULL, 0);
if (errno)
    perror ("strtoul");

The big gotcha

A common problem with error reporting using errno is that there is only one such variable per thread, and that any function you call might change the value. This can also happen for functions that does not use errno for error reporting, because they might call a function that does.

This snippet is buggy because it calls printf before checking if errno == EIO, and printf might change the value of errno.

if (fsync (fd) ==1) {
    fprintf (stderr, "fsync failed!\n");
    if (errno == EIO)
        fprintf (stderr, "I/O error on %d!\n", fd);
}

How to deal with this in Julia

ccall is the special function-like syntax in Julia that allows you to talk to a C-function from Julia on the C-function's terms. If you want to call functions that do error reporting through errno correctly you will have to use the special variant with the same syntax eccall that returns two values. The first is the return value from the C-function, and the second is the value of errno right after the function returned. eccall will of course set errno to zero before calling the function so that you can be sure that the error actually came from that function.

1 buff = "2333"
2 v, err = eccall("strtoul", Uint64, (Ptr{Uint8}, Ptr{Void}, Int), buff, C_NULL, 10)
3 err && throw(SystemError(err, "strtoul failed"))

which should be equivalent to the following C code

// line 1 
char* buff = "2333"
// line 2 
errno = 0;
int v = strtoul(buff, NULL, 10);
int err = errno;
// line 3
if err
    perror("strtoul failed");

Before Julia 0.3 or 0.4?

Early versions of Julia did not expose a special intrinsic eccall for dealing with errno APIs, but had a function called Base.errno() that would allow programmers to access the value of errno, and also a function systemerror, that checked erron and raised an appropriate SystemError. This was deprecated because it was impossible to know if something might cause the value of errno to change between a ccall and when someone checked the error. In julia there is a runtime system with garbage collection and JIT compiling that might stop the execution of your code. Optimizations might also interfere with execution order. The current approach of explicitly storing it is much safer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment