((λ (x) (x x)) (λ (x) (x x)))

Thoughts on Eternity, God, and lesser endeavors

Archive: July 2010

Handling errno in foreign code

, , , ...

If you are writing and interfacing with foreign libraries in Chez Scheme, it's often rather important that you can get efficient access to errno. When I say efficient, I also mean efficient developer time, and not just run time. In sticking with my normal goals, I try to minimize the amount of C code that I have to write for foreign code. It's often more fragile and harder to maintain over time.

But Chez Scheme's FFI, while very powerful and simple, simply doesn't have a specific way to manage error reports coming back. How do you get access to the errno? Is your method thread safe? The calling context switches back and forth between Chez Scheme and foreign code could very well cause errno to be overwritten. How do you handle this?

Well, let's go into some Chez Scheme black magic. Beware! This is unsafe and dangerous if you don't know what you are doing! Don't try this at home kids. ;-)

(define errno
  (let ([errno-ent (#%$foreign-entry "errno")])
    (lambda () (foreign-ref 'int errno-ent 0))))
(define errno-message
  (let ([$strerror (foreign-procedure "strerror"
                     (fixnum)
                     string)])
    (lambda (num) ($strerror num))))
(define (call-with-errno thunk receiver)
  (call-with-values
    (lambda ()
      (critical-section (let ([v (thunk)]) (values v (errno)))))
    receiver))


Alter to taste.

Are computer scientists anti-social?

, ,

It seems like people still have a sort of misconception about Computer Science as a lone wolf art. Some people just don't realize that computer scientists are as social and as friendly as anyone else, but they have a passion, and that passion often can't be shared with others, because others don't understand it. It's the same way with any other artist. People can appreciate the art that an artist renders to some degree, but they probably won't appreciate the real devotion to every aspect of their craft that the artist possesses. Computer scientists are artists. And we love to get together with other people who can share and understand our passion as well.

A wonderful example of this is the OpenBSD hackathon, as described in this article written by J. C. Roberts.

Computer Science Curricula

, , , ...

Those of you who know me and also know that I am a Computer Scientist often ask me, "What programming languages do you use?" I usually tell them that I'll use whatever is the right one for the job, and then qualify that by saying that for over 99% of my work I use either Scheme or C, with most of it being Scheme. To fellow Graduate Computer Scientists or Professors who have done a lot of work with various programming language, this comes as no surprise. To people who are young, self-taught programmers, or who spend most of their time in enterprise or business focused programming positions, this usually surprises them a great deal.

When they ask the inevitable follow-up question, "Why," I can tell them: I find both languages to be the most relatively elegant languages which give me the most productivity when working on the widest range of problems. However, it appears that someone else agrees with me for an entirely different reason.

Joel Spolsky wrote an article some time ago warning against the dangers of using in vogue programming languages to teach Computer Science. He describes two important concepts that make a big difference between mediocre programmers, and good programmers: Recursion and Pointers. He focuses on Java as the danger, but from my own experience, I would have to add languages like Python, which are gaining more popularity in the modern C.S. curricula throughout the United States.

I disagree with Joel when he says that recursion and pointers are hard, giving them merit to weed out the good from the bad programmers. They aren't really hard, but they do require that you wrap your brain around them. However, young kids can pick these ideas up, and it certainly should be possible for College C.S. students to do so.

Interestingly, Joel brings up two languages to highlight recursion and pointers. He points to the classic MIT 6.001 Scheme course which used to be required for all MIT Computer Science undergraduates. He also talks about the structures courses that used to be taught in C throughout the United States. Unfortunately, sometimes these course are now taught in Java, more often than not. I also see system architecture courses being taught in Python. While I don't have anything against these languages for practical use, usually, Joel brings up some really good points about why they aren't necessarily good for teaching these courses.

At the curriculum at IU, I am disappointed with some of the choices to use things like Python and Java in various courses, but I can happily report that many courses still take advantage of C and Scheme. I have a great deal of respect for many of the Professors who care about trying to improve Computer Science, but they often have their hands tied with respect to making these sorts of changes to the curriculum.

So, maybe languages like Scheme and C have something else that I enjoy? Maybe they represent powerful but simple implementations of a core programming methodology that appeals to me. Indeed, I use Scheme for most of my everyday programming because it allows me to express process in the most natural way for any specific purpose, and C is my language of choice when I need to interface with, and control the boundaries between Scheme and the system libraries of my machine.

I should point out that you actually can teach important concepts like these in other languages, but it is much harder to do so. I think the primary point of importance is to focus Computer Science curricula on the foundations and principles of Computer Science, and not on the trendy paradigm of the year. The foundations of computer science transcend the various programming languages and the paradigms that have been built around them. A computer scientist goes beyond the programmer because the computer scientist is able to diverge and adapt through a core knowledge, rather than just having a skill-set which looks good on paper to the latest manager. Better programmers are those who focus on the ideas and the principles of Computer Science, rather than on the language and the frameworks.

Of course, there are many people out there who disagree with me. I call it the difference between raising hackers (in the traditional sense) and raising code monkies.

Bytevectors and Foreign Code

, , , ...

Sometimes when working with bytevectors in Chez Scheme, you want to treat that bytevector as a foreign allocated block of data that you can pass to functions that will be used by the foreign side of code. If the procedure which expects a pointer to a block of memory is already foreign code, that's easy to handle:

(foreign-procedure "my_func" (... u8* ...) ...)

This foreign function will then receive a pointer to the bytevector. Nothing special here, and this is actually a pretty common thing to do. The more annoying case comes the foreign code is actually mapped to a scheme code that needs to treat some of its arguments as return-value arguments. Say for example that you are going to register a foreign callback with a foreign function register_callbacks() that has the following signature:

int64_t callback(char **buf);

Here, the callback is expected to put a pointer to the buffer into its argument, and then return the length as a return value. Ideally, we want to write this callback in Scheme, and we want to have our blocks of data in bytevectors, not in FOREIGN-ALLOC'd pointers that have to be managed manually. However, we can't put a bytevector into a pointer to a pointer to a buffer, because we don't have a means of getting the pointer to the bytevector in Scheme! Or do we?

The trick here is to use a function that will take in a buffer and give you back a pointer to that buffer. It just so happens that memcpy(3) does this:

void *memcpy(void *dst, void *src, size_t count);

We can exploit this fact in Chez Scheme to define something like this:

(define foreign-bytevector-ptr
  (let ([$memcpy (foreign-procedure "memcpy" (u8* uptr unsigned-long) uptr)])
    (lambda (bv)
      (assert (bytevector? bv))
      ($memcpy bv 0 0))))

Voila! Now we can use this to fill our return value argument in our foreign callback that we actually write in Scheme.

(define (callback buf**)
  (let ([bv (get-bv)]
        [bvl (bytevector-length bv)])
    (lock-object bv)
    (foreign-set! 'uptr buf** 0 (foreign-bytevector-ptr bv))
    bvl))

Just remember that you have to lock the bytevector object before you pass it to the foreign side if that vector will be used after the return from the call, because as soon as you re-enter Schemeland, the vector could be relocated by the storage manager. You should also remember to have a way to unlock the object once you know that you no longer need it, so that you don't keep potential memory fragmenters and other efficiency blocks sitting around in the storage manager unnecessarily.

Motif and Slackware 13.1

, , , ...

Unfortunately, there is a bug in X Windows that ships with Slackware64 13.1 which can cause programs which expect a certain behavior in X.org to freeze up. It's quite unpleasant. Fortunately, there is a patch that fixes the problem quite nicely. Here's the patch that I applied to my xorg-server package. This appears when you run the mwm window manager. What a drag.

Path: g2news1.google.com!news2.google.com!news3.google.com!goblin2!goblin.stu.neva.ru!csnews.cs.nctu.edu.tw!news.cs.nctu.edu.tw!ctu-peer!news.nctu.edu.tw!meganewsservers.com!feeder2.on.meganewsservers.com!news.uwaterloo.ca!server.example.net!not-for-mail
From: pab...@plg2.math.uwaterloo.ca (Peter A. Buhr)
Newsgroups: comp.windows.x.motif
Subject: Re: mwm
Date: Fri, 25 Jun 2010 07:54:53 -0400 (EDT)
Organization: University of Waterloo
Lines: 152
Message-ID: <i025ed$c85$1@plg2.math.uwaterloo.ca>
References: <hvjnv7$44a$1@rumours.uwaterloo.ca> <vfn3f7-049.ln1@news.anatron.com.au>
NNTP-Posting-Host: plg2.math.uwaterloo.ca
X-Trace: rumours.uwaterloo.ca 1277466893 8620 129.97.186.80 (25 Jun 2010 11:54:53 GMT)
X-Complaints-To: abuse@uwaterloo.ca
NNTP-Posting-Date: Fri, 25 Jun 2010 11:54:53 +0000 (UTC)

In article <vfn3f7-049....@news.anatron.com.au>,
Russell Shaw  <rjshawN_o@s_pam.netspace.net.au> wrote:
>Peter A. Buhr wrote:
>> I have been using mwm for over 20 years. I just installed Ubuntu 10.4 on my
>> laptop and now when I press Alt-button1 in a window to raise the window
>> (defined in my .mwmrc file), mwm locks up and only allows input into the window
>> where I performed the Alt-button1.
>
>Ask in x...@lists.freedesktop.org
>http://lists.freedesktop.org/mailman/listinfo/xorg

I did ask and it has moved on to this stage (see below). I don't know when the
patch will appear in distros. It appears to be have been a reasonably major bug
and many at xorg were glad it was found. 

I'm pressing to my next problem with a bad interaction between mwm and
arcoread. I'll keep people here informed if I make any progress.

==============================================================================

Date: Fri, 25 Jun 2010 09:48:10 +1000
From: Peter Hutterer <peter.hutte...@who-t.net>
To: "X.Org Devel List" <xorg-de...@lists.freedesktop.org>
Cc: "Peter A. Buhr" <pab...@plg2.math.uwaterloo.ca>,
        Keith Packard <kei...@keithp.com>,
        Daniel Stone <dan...@freedesktop.org>
Subject: [PATCH] Revert "dix: use the event mask of the grab for
 TryClientEvents."
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Behaviour of earlier X servers was to deliver the ButtonPress event
unconditionally, regardless of the actual event mask being set. Thus, a
GrabButton event will always deliver the button press event, a GrabKey
always the key press event, etc. Same goes for XI and XI2.

Reproducible with a simple client requesting a button grab in the form of:
    XGrabButton(dpy, AnyButton, AnyModifier, win, True, ButtonReleaseMask,
                GrabModeAsync, GrabModeAsync, None, None);

On servers before MPX/XI2, the client will receive a button press and
release event. On current servers, the client receives only the release.
Clients that expect the press event to be delivered unconditionally may
leave the user with a stuck grab.

XTS test results for XGrabButton are identical with and without this patch.

This reverts commit 48585bd1e3e98db0f3df1ecc68022510216e00cc.

Conflicts:

	dix/events.c

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
 dix/events.c |   52 ++--------------------------------------------------
 1 files changed, 2 insertions(+), 50 deletions(-)

diff --git a/dix/events.c b/dix/events.c
index ae9847c..e1c3d0a 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3420,7 +3420,6 @@ CheckPassiveGrabsOnWindow(
     {
 	DeviceIntPtr	gdev;
 	XkbSrvInfoPtr	xkbi = NULL;
-	Mask		mask = 0;
 
 	gdev= grab->modifierDevice;
         if (grab->grabtype == GRABTYPE_CORE)
@@ -3535,9 +3534,6 @@ CheckPassiveGrabsOnWindow(
                 }
                 xE = &core;
                 count = 1;
-                mask = grab->eventMask;
-                if (grab->ownerEvents)
-                    mask |= pWin->eventMask;
             } else if (match & XI2_MATCH)
             {
                 rc = EventToXI2((InternalEvent*)event, &xE);
@@ -3549,34 +3545,6 @@ CheckPassiveGrabsOnWindow(
                     continue;
                 }
                 count = 1;
-
-                /* FIXME: EventToXI2 returns NULL for enter events, so
-                 * dereferencing the event is bad. Internal event types are
-                 * aligned with core events, so the else clause is valid.
-                 * long-term we should use internal events for enter/focus
-                 * as well */
-                if (xE)
-                    mask = grab->xi2mask[device->id][((xGenericEvent*)xE)->evtype/8];
-                else if (event->type == XI_Enter || event->type == XI_FocusIn)
-                    mask = grab->xi2mask[device->id][event->type/8];
-
-                if (grab->ownerEvents && wOtherInputMasks(grab->window))
-                {
-                    InputClientsPtr icp =
-                        wOtherInputMasks(grab->window)->inputClients;
-
-                    while(icp)
-                    {
-                        if (rClient(icp) == rClient(grab))
-                        {
-                            int evtype = (xE) ? ((xGenericEvent*)xE)->evtype : event->type;
-                            mask |= icp->xi2mask[device->id][evtype/8];
-                            break;
-                        }
-
-                        icp = icp->next;
-                    }
-                }
             } else
             {
                 rc = EventToXI((InternalEvent*)event, &xE, &count);
@@ -3587,23 +3555,6 @@ CheckPassiveGrabsOnWindow(
                                 "(%d, %d).\n", device->name, event->type, rc);
                     continue;
                 }
-                mask = grab->eventMask;
-                if (grab->ownerEvents && wOtherInputMasks(grab->window))
-                {
-                    InputClientsPtr icp =
-                        wOtherInputMasks(grab->window)->inputClients;
-
-                    while(icp)
-                    {
-                        if (rClient(icp) == rClient(grab))
-                        {
-                            mask |= icp->mask[device->id];
-                            break;
-                        }
-
-                        icp = icp->next;
-                    }
-                }
             }
 
 	    (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE);
@@ -3612,7 +3563,8 @@ CheckPassiveGrabsOnWindow(
             {
                 FixUpEventFromWindow(device, xE, grab->window, None, TRUE);
 
-                TryClientEvents(rClient(grab), device, xE, count, mask,
+                TryClientEvents(rClient(grab), device, xE, count,
+                                       GetEventFilter(device, xE),
                                        GetEventFilter(device, xE), grab);
             }
 
-- 
1.7.1