PreviousUpNext

15.4.1194  src/lib/std/src/threadkit/posix/retry-syscall-on-eintr.pkg

## retry-syscall-in-eintr.pkg
#
# Some system calls may take a long time
# to complete and may be interrupted by
# timer signals before they complete.
#
# This module implements a simple hack to
# partially protect against this problem.
#
# For a longer discussion see comments at bottom of:
#
#     src/c/lib/socket/connect.c
#
# This hack gets used in:
#     src/lib/x-kit/xclient/pkg/wire/display.pkg

# Compiled by:
#     src/lib/std/standard.lib





stipulate
    package log =  logger;                                      # logger                is from   src/lib/src/lib/thread-kit/src/lib/logger.pkg
    package ts  =  thread_scheduler;                            # thread_scheduler      is from   src/lib/src/lib/thread-kit/src/core-thread-kit/thread-scheduler.pkg
    package psx =  posix_1003_1b;                               # posix_1003_1b         is from   src/lib/std/src/posix-1003.1b/posix-1003-1b.pkg
herein

    package retry_syscall_on_eintr: (weak)    api {

        is_intr:  winix::System_Error -> Bool;
            #
            # Return TRUE iff error was due to system
            # call being interrupted -- that is, if it
            # returned posix EINTR in errno.

        do_syscall_retry_on_eintr:  (X -> Y) -> X -> Y;
            #
            # Do a system call, and restart if it is interrupted
            # (that is, if it returns posix EINTR in errno).

        do_atomic_syscall:  (X -> Y) -> X -> Y;
            #
            # Do a system call with timer signals masked (i.e., SIGALRM ignored) 

        tracing:  file::Logtree_Node;           # Controls printing of thread watching messages.
    } {

        tracing =  log::make_logtree_leaf { parent => file::all_logging, name => "retry_syscall_tracing" };
        to_log  =  log::log_if  tracing;                        # Conditionally write strings to tracing.log or whatever.
            #
            # To debug via tracelogging, annotate the code with lines like
            #
            #   to_log .{ sprintf "foo/top: bar d=%d" bar; };

        fun is_intr err
            =
            err == psx::error::intr;            # == posix EINTR.


        
        fun do_atomic_syscall f x
            =
            {
                # Note that stopping the timer will stop all
                # thread_scheduler timeslicing dead in its
                # tracks, including all threads attempting to
                # maintain periodic user interface stuff etc.
                #
                # This is probably a REALLY BAD IDEA.           XXX BUGGO FIXME
                #
                ts::stop_thread_scheduler_timer();
                    #
                    # XXX BUGGO FIXME this is still pretty slapdash;
                    #                 we can still get interrupted by
                    #                 signals like SIGCHLD, and if we
                    #                 do we're screwed.

                result =    (f x)
                            except
                                x = {
                                        ts::restart_thread_scheduler_timer ();
                                        raise exception x;
                                    };

                ts::restart_thread_scheduler_timer ();

                result;
            };


        # This function is only called in
        #
        #     src/lib/std/src/posix/threadkit-winix-data-file-io-driver-for-posix.pkg
        #
        # where it protects a few read() and write() calls;
        # if any other "slow" system call is interrupted,
        # we are still screwed. :-(             XXX BUGGO FIXME
        #
        fun do_syscall_retry_on_eintr f x
            =
            try 3
            where

                fun try 0
                        =>
                        do_atomic_syscall f x;

                    try n
                        =>
                        (f x)
                        except
                            (ex as winix::RUNTIME_EXCEPTION(_, THE err))
                                =
                                if (is_intr err)      try (n - 1);
                                else                  raise exception ex;
                                fi;

                end;
            end;
    };

end;


## COPYRIGHT (c) 1996 AT&T Research.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2012,
## released under Gnu Public Licence version 3.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext