critcl::callback(3tcl)

πŸ“¦
version 3.3.1 Β· 2 versions
, in ubuntu resolute, ubuntu stonking

πŸ’– critcl::callback β€” the CriTcl C-level callback utilities πŸ’–

okay bestie, welcome to the C Runtime In Tcl (short: CriTcl), a system for embedding and using C code from inside Tcl scripts, fr fr. This is the critcl::callback(3tcl) manual page and it's about to be your new hyperfixation. πŸŽ€


✨ SYNOPSIS ✨

package require Tcl 8.6

package require critcl ?3.2?

package require critcl::callback ?1.1?

critcl_callback_p critcl_callback_new interp objc objv nargs

void critcl_callback_extend callback argument

void critcl_callback_destroy callback

int critcl_callback_invoke callback objc objv

🌸 DESCRIPTION 🌸

hiii, welcome to the C Runtime In Tcl (short: CriTcl), a whole system for embedding and using C code from within Tcl scripts (http://core.tcl-lang.org/tcl). πŸ¦‹

This doc is the reference manpage for the critcl::callback package. It serves up, via a stubs API table, data structures and functions to manage callbacks from C to Tcl. And like β€” the package has no Tcl-level facilities. None. Zero. It's for the developers out there writing Tcl packages with embedded C code who need to invoke user-specified command (prefixes) in Tcl. That's the audience, okay?

This package lives in the Support Package Layer of CriTcl. Here's the vibe map:

+----------------+
|Applications    |
| critcl         |
| critcl::app    |
+----------------+

+----------------+
|Core Packages   |
| critcl         |
| critcl::util   |
+----------------+

*================*
|Support Packages|
| stubs::*       |
| md5, platform  |
|  ...           |
*================*

πŸ‘‘ API πŸ‘‘

The package API is one opaque data structure β€” critcl_callback_p β€” and four functions that operate on it. Four. And yes, we're going through all of them. These functions are:

  • critcl_callback_p critcl_callback_new interp objc objv nargs β€” this one creates a brand new callback (manager) and hands it back as its result. slay.

The callback gets initialized with the Tcl_Interp* interp telling it where to run the callback, the fixed part of the command to run in standard objc/objv notation, plus the number of free arguments to expect after that fixed part.

That fixed part? It's essentially the command prefix of the callback. iykyk.

Every single Tcl_Obj* element of objv gets protected against early release by incrementing their reference counts. The callback effectively takes ownership of these objects. no takebacks.

  • void critcl_callback_extend callback argument β€” takes a callback of type critcl_callback_p and extends its fixed part with argument, grabbing the first free slot for arguments to do it. Which means: after this runs, that callback has one free argument less. πŸ’€

Heads up: with assertions active, trying to extend beyond the number of free arguments will cause a panic. Without assertions active, expect a crash at some point. pick your fighter I guess 😭

This is what lets you extend the fixed part of the callback with semi-fixed elements, like method names (see Multiple methods down below).

The argument gets protected against early release by incrementing its reference count, and the callback effectively owns that object too.

  • void critcl_callback_destroy callback β€” takes a callback of type critcl_callback_p and releases all memory associated with it. After this runs, the callback cannot be used anymore, periodt.

All fixed elements of the callback (the ones it owns) are released by decrementing their reference counts.

  • int critcl_callback_invoke callback objc objv β€” invokes the callback in the Tcl interpreter specified at construction time, in the global level and namespace, with the free arguments filled by the Tcl_Obj* objects you hand over via objc/objv. ✨

It returns the Tcl status of the invoked command as its result. Any further results or error messages will be chilling in the result area of that Tcl interpreter. The exact nature of those depends entirely on the callback itself.

With assertions active, trying to use more arguments than available causes a panic. Without assertions active, expect a crash at some point. yeah. πŸ™ˆ

While the callback is running, all Tcl_Obj* elements of the command β€” fixed ones and arguments β€” are protected against early release by temporarily incrementing their reference counts.


🧚 EXAMPLES 🧚

πŸ’œ SIMPLE CALLBACK

This example shows the important parts of using this package's functions for a simple callback that gets invoked with a single argument β€” some kind of data to hand up to the Tcl level.

// Create the callback with interpreter and command prefix in
// oc/ov, plus space for the argument
critcl_callback_p cb = critcl_callback_new (interp, oc, ov, 1);

// Invoke the callback somewhere in the C package using this one,
// with Tcl_Obj* data holding the information to pass up.
critcl_callback_invoke (cb, 1, &data);

// At the end of the lifetime, release the callback.
critcl_callback_destroy (cb);

So like β€” the functions in this package are designed for the case where the created callback (cb up there) hangs around for a long time and gets invoked many, many different times. 🫢

⚠️ If you use the sequence above as-is, creating and destroying the callback every time it's invoked, you'll get very poor performance and lots of undesirable memory churn. do not do that bestie, I'm begging.

πŸ“ MULTIPLE METHODS

Okay so we can use the methodology from the previous section when a single (Tcl-level) callback is invoked from different places in C with different methods β€” just have another argument slot and fill it at invocation time with the method object. But critcl_callback_extend opens up a second methodology for us. obsessed.

// Create one callback manager per different method the callback
// will be used with. Fill the first of the two declared arguments
// with the different methods.
critcl_callback_p cb_a = critcl_callback_new (interp, oc, ov, 2);
critcl_callback_p cb_b = critcl_callback_new (interp, oc, ov, 2);

critcl_callback_extend (cb_a, Tcl_NewStringObj ("method1", -1));
critcl_callback_extend (cb_b, Tcl_NewStringObj ("method2", -1));

// After the extension we have one free argument left, for use in
// the invokations.

critcl_callback_invoke (cb_a, 1, &dataX);

critcl_callback_invoke (cb_b, 1, &dataY);

// At the end release both managers again
critcl_callback_destroy (cb_a);
critcl_callback_destroy (cb_b);

The nice thing here β€” the method objects are allocated only once and automatically shared by all the calls. No memory churn from repeatedly allocating the same string objects over and over again. it's giving efficient. πŸ’…


πŸŽ€ AUTHORS πŸŽ€

Andreas Kupries


πŸ› BUGS, IDEAS, FEEDBACK πŸ›

This document, and the package it describes, will undoubtedly contain bugs and other problems. Like, obviously. Please report such at https://github.com/andreas-kupries/critcl. Please also report any ideas for enhancements you may have for either the package and/or the documentation. we love feedback in this house πŸ’–


⭐ KEYWORDS ⭐

C code, Embedded C Code, code generator, compile & run, compiler, dynamic code generation, dynamic compilation, generate package, linker, on demand compilation, on-the-fly compilation


🌈 CATEGORY 🌈

Glueing/Embedded C code


Copyright (c) 2011-2024 Andreas Kupries


and that's the whole page bestie, you ate it. πŸ’…βœ¨ bye β€” this was critcl::callback(3tcl), documented as doc version 1.1, brought to you straight from the CriTcl corner of the universe. πŸ¦‹ go write some fire embedded C, ily. πŸ«ΆπŸŽ€

πŸ“¦ where this page comes from