Þ   briarpig  » story  » vtables


Wil is a fictional developer arguing with a junior coder named Hal about the use of vtables: which party does space allocation? The library or the client? Wil says client allocation is best since it shows errors earlier — at link time instead of run time. (This story is short, and there's less to say, so the right column is used as an excuse to introduce a new character in unfocused fiction.)

     As in Hal's first appearance in tombstones, Hal has traces of native Russian accent and phrasing — in small doses — and Wil still curbs his vocabulary more than usual.

embedding

     Che still had Hal assigned to handle Wil's lesser tasks so Wil's critical path load might be reduced. But tasking Hal forced Wil to do non-critical problems first, often taking longer than if Wil did them alone. Che kept everyone busy by upping Wil's pressure.

     Hal asked Wil to task him with something, so Wil suggested Hal finish replacing direct calls to system APIs with indirect calls through a vtable Wil provided. Wil explains the concept of vtables below, but most of this story is about Hal's idea to alter vtable allocation to prevent a link error he found.

     As Wil explains at the end, a link error is preferrable. Before Hal's idea is presented, first look at Wil's vtable style.

     The general idea is a technique common to embedded systems, using an "inversion of control" pattern deferring some actions to an environment without hard-coding them.

     Wil added a vtable (for function call indirection) to a library when it needed to link inside an app refusing a dependency on system calls like mmap(). Wil was able to structure the library so another i/o option could be used instead, so mmap() was not required. However, if a client did want memory mapping for i/o, this could still be done if a client provided mmap() related function pointers.

     The example vtable below shows only a few function pointers — just enough to establish the right idea. First Wil defines typedefs for function pointers with signatures exactly matching system calls malloc() and mmap(), so these can be used in a vtable

     Note all symbols shown use a mu_ namespace prefix. The suffix _m at the end of a symbol is convention for "method."

/*include <stdlib.h>: void* malloc(size_t size);*/ typedef void* (*mu_malloc_m)(size_t size); /*include <sys/types.h>, include <sys/mman.h>*/ /*void* mmap(void*, size_t, int, int, int, off_t);*/ void* (*mu_mmap_m)(void* p, size_t n, int prot, int flg, int fd, off_t off);

     (Wil usually includes both malloc() and free() in vtable methods because many folks have an idea these often need indirection. So adding them to a vtable is simpler than explaining neither is a system call — both are usually weakly linked so an app can replace them simply by defining and linking replacements. When folks ask Wil if they can replace allocation with anything they want, Wil can just say yes and point at relevant vtable slots.)

     Given these typedefs for mu_mmap_m and mu_malloc_m function pointers, Wil defines a vtable struct as follows:

typedef struct mu_vt mu_vt; struct mu_vt { /*vtable format*/ mu_malloc_m vt_malloc_fn; mu_mmap_m vt_mmap_fn; };

     Note these two methods are just representative — the actual list of vtable methods is as many as one needs to indirect through a vtable: every call one wants to support weakly or optionally. A vtable permits late binding to methods.

     An actual client api using a vtable consists of a caller-supplied vtable pointer and wrapper methods with the same signature as the original methods indirecting through the vtable:

extern g_mu_vt* mu_vt; /*client must define*/ static inline void* mu_malloc(size_t size) { mu_malloc_m fn = (g_mu_vt)? g_mu_vt->vt_malloc_fn: 0; return (fn)? (*fn)(size) : 0; } static inline void* mu_mmap(void* p, size_t n, int prot, int flg, int fd, off_t off) { mu_mmap_m fn = (g_mu_vt)? g_mu_vt->vt_mmap_fn: 0; if (fn) return (*fn)(p, n, prot, flg, fd, off); errno = ENOSYS; return (void*) -1; /*error return for mmap()*/ }

     Now the library simply replaces all malloc() calls with mu_malloc(), and all mmap() calls with mu_mmap(). Then the library no longer links against the original calls. They only become reachable if a client using the api puts non-nil function pointers in the vtable instance to which g_mu_vt points.

missing vtable

     What happens if a client forgets to define a g_mu_vt pointer? It causes a link error when that symbol is not defined. This is what Hal hit when replacing malloc() calls with mu_malloc() calls everywhere, even in executables for unit tests which didn't mean to use the library api involved, but nevertheless stopped calling malloc() because Hal was thorough.

     Hal suggested, "I have idea for better way to do it, so link error does not happen."

     After five minutes of questioning, Wil finds Hal wants the library to define a pointer so clients need not do it themselves.

     "But that's the same thing," Wil objects. "What is the bad part about having the client define the pointer?"

     "Current way is worse for client," Hal explains. "Missing definition causes link error. Library can prevent link error by defining both vtable and pointer both. Only function pointers need to be set. I feel this is very much better way to do it."

     Wil thought a minute, realizing he chose the current style on purpose, since it reveals problems earlier. So he tried to explain. But Hal rarely hears more than ten words before interrupting. Wil got annoyed Hal only listened to see if Wil agreed with Hal.

     "If I do it your way," Wil finally explained, "no link error will occur, but code fails at run time when no function pointer is put into the vtable."

     "Is this a problem?" Hal asked.

     "Yes," Wil insisted. "A developer will only see the call failed, and won't get much explanation why. Instead of a clear link error at development time revealing something must be done, a developer only gets mysterious bad behavior sometime in the future, maybe when someone else runs the unit test."

     "I think that's maybe okay," Hal equivocated.

     "It's terrible," Wil insisted. "Think of virtual C++ functions: if you forget to define virtual methods, you get link errors, right?"

     Hal nodded: C++ virtual functions were good.

     Wil continued, "You're saying you'd rather a missing virtual method just fail without explanation when run."

     Hal held up his hands, saying, "We can keep your design if it matters a lot to you. I just make suggestion."

     Wil tried to explain why he was unhappy. "I need to stop working on trivial link problems. We're not making progress because I'm not writing code that's missing. Linking won't matter if the library cannot work because I didn't finish it."

     "What should I do now?" Hal asked.

     "Look at the code," Wil suggested, "and try to guess what it might aim to do, then decide whether existing code actually does what's intended. Or call the code from tests — when surprised by results, try to figure out how actual behavior differs from what should happen."

     Wil opened a file and showed Hal a few methods that were merely stubs waiting to be filled with code.

     "You can try to work out what code should go here," Wil suggested. "I've documented what should happen — no one reads that though. You have the old system to see context of earlier use. You can see existing code that will be called to make these work. If I already knew exactly how to connect the dots I'd have them written. You can take a shot."

     Hal looked glum. "I will try," he offered.

     Wil stared at his monitor, trying to get his blood pressure to go down. Twenty minutes wasted on nonsense, and another twenty of rattled steaming before back in a groove again.

Beware strange motifs or plot turns: at least one obligatory weird thing appears in each story page by convention.

     On the use of story format to convey ideas, see 03feb08 and background for brief explanations. The right column below features pure fiction mostly unrelated to tech in the left column. For a short critique on what's wrong with this particular story (so many problems) see 01mar08.

premise

     As Wil writes (column left) on Saturday morning, Zé drops in to meet Ulf's college age son Eli — Zé wanted to meet Eli as a potential site participant in story writing. Ulf said they'd come by. Of this first meeting, the tale below is one part taken out of context.

     Zé thinks a young person might inspire an ensemble of game players: old timers might take less for granted, sometimes explaining obvious or assumed facts. (In a time-honored use of naive foils in fiction, ignorance can draw random mysticism and philosophy from elders, at times to comic effect.)

boundaries

     Z walked into Wil's place without knocking, heading for the living room where the PS2 was setup with Jak 3. As expected, Wil was writing in his faux cube, which really freaked out Ulf when he first saw it. Why would anyone come home from working in a cube farm, then go directly to another cube in his living room?

     Z thought it was pretty funny. He and Wil had similar senses of humor. Now if only Wil would start calling him Z instead of Zé. But old habits are hard to lose, and Wil learned to say Zé or Zeta too often when they roomed years ago. Z was on a progressive abbreviation kick, but Wil didn't care beyond joking whitespace would be even shorter. Z called himself Z mainly in internal dialog. Maybe it was the same as 'I'. But cooler.

     "Elvis has entered the building," Z said falling into the couch, because Wil hadn't looked up.

     Wil clicked his tongue once in response. This was geek humor meaning a single bit of one. Wil did it sometimes to say "of course", or "duh", or "tell me something I didn't know" depending on context. When paired with a goofy look and a three stooges posture it meant soitenly. Wil had trouble engaging verbal circuits when writing or coding, apparently because he used the speaking part of his brain for something else when working.

     Z loaded a game in hero mode then settled into killing marauders in the desert before starting hang time jumps off the dunes. Ulf and Eli weren't due for a while yet. Z wondered how different father and son could look from each other. Martin Sheen's sons Charlie Sheen and Emilio Estevez hardly looked like brothers at all, but of course they had different mothers. "Somebody threw away a perfectly good white boy," Z said to himself.

     Wil snorted quietly.

     As his vehicle slid out of control in the sand after a bad landing, Z imagined a new mission for Jak in the desert, involving an arabian princess and opulent tent furnishings. Except his sidekick — a talking camel with a witty tongue — just wouldn't shut up. The princess kept laughing, though. "You're the sidekick, Wil," Z said.

     "No, you're the sidekick," Wil shot back. Apparently his speech center wasn't that busy after all — or this reply was pure reflex by now.

repo man

     Eli didn't look much like his father, but their voices were alike, so he couldn't be a changeling Zé concluded. He was also far more polite than Ulf, and only stared a bit too long when they met. "Portugese-Irish-Brazilian," Zé had finally answered Eli's unasked question.

     "When's Koi giving a green light?" Ulf asked.

     Zé shrugged. "Ask him yourself. If you want him to go faster, write some fiction. Give Koi more to go on."

     Eli hadn't said much so far, but slowly his initial tense awareness of scrutiny faded away, as he casually examined junk around Wil's place. He seemed like a bright kid about 20 years old, with quite a long attention span. A twinkle appeared in Eli's eye every time Zé gave Ulf a little grief. Now a playful smile appeared.

     "Yeah, dad," Eli jibed, "Get off your butt and write some fiction. And get a haircut while you're at it."

     "Oh, I don't know," Ulf whined, "Maybe I'll apply myself after I take time off." This definitely had an edge, likely related to Ulf's complaint Eli left school recently to consider other options. Sounded like a stale fight.

     No one said anything for a moment; the sound of Wil typing dominated the room. After initial introductions and chatting, Wil had asked if he could finish a few paragraphs before stopping. How could they say no? Zé decided to show them something funny to break the tension. So he cleared his throat and pitched his voice in imitation of someone else.

     "Ever been to Utah?" Zé asked. Eli hesitated, and Wil broke in first, but continued typing.

     "Ra-di-a-tion," Wil said carefully. "Yes, indeed."

     "You hear the most outrageous lies about it," Zé prompted as if he really meant it. Ulf's eyebrows went up because this looked like a performance. Wil kept writing and never slackened typing.

     "Pernicious nonsense," Wil continued. "Everybody could stand a hundred chest X-rays a year."

     Eli laughed, interrupting to add: "They ought to have them, too." Zé smiled hugely when Eli recognized this bit, but Ulf was completely lost.

     Eli put on a face and started to get into character. His idea of mad scientist was a bit campy. "When they canceled the project it almost did me in," Eli emoted.

     Wil spun around in his aeron chair after saving a document with theatrical flourish. He looked happy, and the smile looked oddly out of place. Wil's normal look in his living room cube was gloomy.

     "I forget the next part, though," Eli pleaded.

     "'One day my mind was full to bursting'," lead Wil.

     "The next day — nothing," Eli remembered. "Swept away." But he hammed his acting.

     "What the hell is this?" demanded Ulf.

     "It's Repo Man, dad," explained Eli.

     "Didn't that come out before you were born?" wondered Ulf, feeling off balance.

     "Duh, free movie channel," Eli zinged.

     "'The more you drive, the less intelligent you are'," Ulf tried. "That one?"

     "'Yeah," confirmed Zé. "At Youtube you can see the scene we just quoted about a minute into a clip."

     "Who's the old guy in the Chevy Malibu again?" asked Eli. "Father of the neutron bomb?"

     "J. Frank Parnell," Zé answered. "Otto finally catches his car after a great guitar lick by Iggy Pop in the sound track." Zé added, "You look a bit like Emilio Estevez."

     Eli shook his head no, and Wil squinted. "Only slightly," Wil decided. "We all look geekier than film stars."

     Interestingly, Eli started to look bored, apparently because adults had once again fallen into the habit of discussing appearance. Good for you, Wil thought. Best to ignore anything that smacks of flattery.

     "Put it on a plate son, you'll enjoy it more," Wil suggested. This was a stupid remark by a parent in Repo Man when Otto ate directly from a can marked "Food" with a generic label. Wil wondered if Eli could relate.

     Eli smiled grimly and his eyes flicked to Ulf.

     "You look smarter than your pa, kid," Zé told Eli. "Is he slow at home too?"

     "Hey, I'm standing right here," objected Ulf.

     "What's his IQ?" Zé asked Wil, then grinned at Ulf.

     Wil stood up and squared his feet to address Eli, who looked nervous. Wil pooched out his belly, hooked his thumbs in his belt, and spoke in a pompous rural drawl like a hill-billy sheriff. "Boy," Wil demanded, "What do you know about history?" Each vowel was a dipthong.

     As luck had it, Eli was playing with a Sharpie pen before this started. Raising it now, he waggled it like a cigar and got a zany look in his eye, while bending slightly at the knees to get a limber stance. This gave him a couple seconds more to decide what to say, Wil could see.

     "Well," Eli said from the side of his mouth, "my roomie in college was poly sci, and he taught me Karl Marx was the funniest of the Marx Brothers."

     "About one fifty," Wil said turning to Zé.

     "You're kidding," Ulf bleated.

     "Your dad has no sense of humor at all, does he?" Zé asked Eli wonderingly.

     "Not as far as I can tell," Eli admitted.