asoma.dev · the C reference for libose
libose
the C library every o.se host is built on
Loading...
Searching...
No Matches
ose_context.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019-23 John MacCallum Permission is hereby granted,
3 free of charge, to any person obtaining a copy of this software and
4 associated documentation files (the "Software"), to deal in the
5 Software without restriction, including without limitation the
6 rights to use, copy, modify, merge, publish, distribute, sublicense,
7 and/or sell copies of the Software, and to permit persons to whom
8 the Software is furnished to do so, subject to the following
9 conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
22*/
23
31#ifndef OSE_CONTEXT_H
32#define OSE_CONTEXT_H
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38#include <inttypes.h>
39#include "ose.h"
40
45#define OSE_CONTEXT_ALIGNMENT 4
46
47/* The cache holds OSE_CONTEXT_NUM_CACHE_ITEMS pointers -- 56 bytes with its
48 * header. The remainder of OSE_CONTEXT_CACHE_SIZE is headroom, and it is not
49 * free: it is paid per context message, and a machine with an inner carries
50 * about a dozen of them. At a 256-byte cache that came to 332 bytes of
51 * overhead per context, 260 of it this blob.
52 *
53 * It cannot be sized per context without giving up compile-time register
54 * offsets: ose_vm.h derives OSEVM_INPUT_CONTEXT_MESSAGE_OFFSET and its four
55 * siblings from OSE_CONTEXT_BUNDLE_OFFSET, which is a constant only because
56 * this is. So it is sized per build, where a host that knows its own
57 * constraints can answer -- an MCU differently from a laptop.
58 *
59 * On AVR a pointer is two bytes, so the three items fit in 36 and the
60 * default is exactly that: the 28 bytes of headroom are paid by every
61 * register on a part with 8 KB of RAM. A size too small for the items is
62 * refused when ose_context.c compiles. */
63#ifdef OSE_CONF_CONTEXT_CACHE_SIZE
64#define OSE_CONTEXT_CACHE_SIZE OSE_CONF_CONTEXT_CACHE_SIZE
65#elif defined(__AVR__)
66#define OSE_CONTEXT_CACHE_SIZE 36
67#else
68#define OSE_CONTEXT_CACHE_SIZE 64
69#endif
70#define OSE_CONTEXT_NUM_CACHE_ITEMS 3
71#define OSE_CONTEXT_CACHE_TYPETAG_STRLEN 8
72
73#define OSE_CONTEXT_BUNDLE_SIZE_OFFSET -4
74#define OSE_CONTEXT_TOTAL_SIZE_OFFSET -8
75#define OSE_CONTEXT_PARENT_BUNDLE_OFFSET_OFFSET -12
76#define OSE_CONTEXT_STATUS_OFFSET -16
77#define OSE_CONTEXT_MEMUSAGE_OFFSET -20
78#define OSE_CONTEXT_CHANGED_OFFSET -24
79/* The context message's typetags are ",bbbiiiiibb": a cache blob, then two
80 * blobs that are unused. An empty blob is exactly the four bytes of its own
81 * size word, and an int32 is four bytes too, so spelling the second as `i`
82 * changes the typetag string and nothing else -- same offsets, same
83 * OSE_CONTEXT_BUNDLE_OFFSET, same padded typetag length. -32 remains unused.
84 *
85 * libose stores this word and does not read it. No bit is named here, which
86 * is the split ose_vm.h keeps for declarations: ose manipulates, and its
87 * clients interpret. A register that must not travel, or one destroyed when
88 * its machine goes idle, are facts about saving and driving, and libose does
89 * neither, so it has no way to be right about them. Whichever client saves
90 * and drives names the bits. */
91#define OSE_CONTEXT_FLAGS_OFFSET -28
92#define OSE_CONTEXT_CACHE_OFFSET -(36 + OSE_CONTEXT_CACHE_SIZE)
93
94void ose_context_set_status(ose_bundle b, int32_t s);
95int32_t ose_context_get_status(ose_bundle b);
107uint32_t ose_context_get_version(ose_bundle b);
118void ose_context_set_flags(ose_bundle b, int32_t flags);
119int32_t ose_context_get_flags(ose_bundle b);
120/* void ose_context_set_cachefns(ose_bundle B, */
121/* int32_t (*getFirstOffsetForMatch)(ose_bundle, */
122/* const char * const, */
123/* void**), */
124/* void *userdata); */
125void ose_context_cache_set(ose_bundle B,
126 int32_t o,
127 void *i);
128void ose_context_cache_setGetFirstOffsetForMatchFn(ose_bundle B,
129 int32_t (*getFirstOffsetForMatch)(ose_bundle,
130 const char * const,
131 void**));
132void ose_context_cache_setUserdata(ose_bundle B,
133 void *userdata);
134
135/* The pair to ose_context_cache_setUserdata(). A cache owner that keeps a
136 sized allocation here needs to read the pointer back in order to report
137 how much of it is in use. */
138void *ose_context_cache_getUserdata(ose_bundle B);
139void ose_context_cache_setTypeBundle(ose_bundle B,
140 ose_bundle tx);
141int32_t ose_context_getFirstOffsetForMatch(ose_bundle B,
142 const char * const address);
143ose_bundle ose_getTypeBundle(ose_constbundle bundle);
144
145#ifdef OSE_MEMPROFILE
146int32_t ose_get_memusage(ose_bundle b);
147void ose_reset_memusage(ose_bundle b);
148#else
149#define ose_get_memusage(b) do{}while(0)
150#define ose_reset_memusage(b) do{}while(0)
151#endif
152
153
154
178#define OSE_CONTEXT_MESSAGE_TYPETAGS ",bbiiiiiibb"
179
183#define OSE_CONTEXT_MESSAGE_TYPETAGS_PLEN 12
184
185#define OSE_CONTEXT_BUNDLE_OFFSET \
186 (4 /* size */ \
187 + 4 /* padded address len */ \
188 + 12 /* padded typetag str */ \
189 + OSE_SIZEWORD_LEN_ + OSE_CONTEXT_CACHE_SIZE /* blob - cache */ \
190 + 4 /* blob - unused */ \
191 + 4 /* int - flags */ \
192 + 4 /* int - changed */ \
193 + 4 /* int - memusage */ \
194 + 4 /* int - status */ \
195 + 4 /* int - offset to bundle */ \
196 + 4 /* int - total size */ \
197 + 4) /* blob size */
198
199
200
201
202int32_t ose_readSize(ose_constbundle bundle);
203
204
205
206
210#define OSE_CONTEXT_MESSAGE_OVERHEAD \
211 (OSE_CONTEXT_BUNDLE_OFFSET \
212 + OSE_BUNDLE_HEADER_LEN_ /* bundle header */ \
213 + 4) /* blob size */
214
215
216
217
221#define OSE_CONTEXT_STATUS_MESSAGE_SIZE 16
222
223
224
225
229#define OSE_CONTEXT_TYPE_MESSAGE_SIZE 1024
230
231
232
233
237#define OSE_CONTEXT_MAX_OVERHEAD \
238 ((OSE_CONTEXT_ALIGNMENT) \
239 + OSE_BUNDLE_HEADER_LEN_ \
240 + OSE_CONTEXT_MESSAGE_OVERHEAD \
241 + OSE_CONTEXT_STATUS_MESSAGE_SIZE \
242 + OSE_CONTEXT_MESSAGE_OVERHEAD \
243 + OSE_CONTEXT_MESSAGE_OVERHEAD \
244 + OSE_CONTEXT_TYPE_MESSAGE_SIZE)
245
246
247
248
258int32_t ose_init(ose_bundle bundle,
259 int32_t size,
260 const char * const address);
261
262
263
264
265
276 int32_t size,
277 const char * const address);
278void ose_dropContextMessage(ose_bundle bundle);
279
280/* Which registers a machine has, and where they sit, is its root bundle's
281 * own version (ose_context_get_version()): making or dropping a register
282 * moves it, and a machine built again in the same bytes goes on from the
283 * version the last one reached. Nothing counts changes across machines;
284 * libose keeps no state outside a bundle. */
285
286
287
288
289
296int32_t ose_spaceAvailable(ose_constbundle bundle);
297
298
299
300
309 const char * const address);
310
311
312
313
314
324 int32_t offset);
325
326
327
328
342 const char * const address);
343
344
345
346
347
354ose_bundle ose_exit(ose_constbundle bundle);
355
356
357
358
359
385int ose_addToSize(ose_bundle bundle, int32_t amt);
386int ose_incSize(ose_bundle bundle, int32_t amt);
387int ose_decSize(ose_bundle bundle, int32_t amt);
388
389
390
391
392
400/* void ose_copyBundleElemToDest(ose_bundle src, ose_bundle dest); */
401
402
403
404
405
413/* void ose_copyBundleElemToDestAddr(ose_bundle src, const char * const dest_addr); */
414
415
416
417
418
426/* void ose_moveBundleElemToDest(ose_bundle src, ose_bundle dest); */
427
428
429
430
431
439/* void ose_moveBundleElemToDestAddr(ose_bundle src, */
440/* const char * const dest_addr); */
441
442
443
444
445
456/* void ose_replaceBundleElemInDest(ose_bundle src, ose_bundle dest); */
457
458
459
460
461
472/* void ose_replaceBundleElemInDestAddr(ose_bundle src, */
473/* const char * const dest_addr); */
474
475
476
477
478
485void ose_copyBundle(ose_constbundle src, ose_bundle dest);
486
487
488
489
490
504
505
506
507
532void ose_copyElemAtOffset(int32_t srcoffset,
533 ose_constbundle src,
534 ose_bundle dest);
535#define ose_copyElem(src, dest) \
536 ose_copyElemAtOffset(ose_getLastBundleElemOffset(src), \
537 src, dest)
538#define ose_moveElem(src, dest) \
539 { \
540 int32_t o = ose_getLastBundleElemOffset(src); \
541 ose_copyElemAtOffset(o, src, dest); \
542 ose_dropAtOffset(src, o); \
543 }
544
545
546
547
548int32_t ose_routeElemAtOffset(int32_t srcoffset,
549 ose_constbundle src,
550 int32_t prefixlen,
551 ose_bundle dest);
552
553
554
555
556
568ose_bundle ose_newBundleFromCBytes(int32_t nbytes, char *bytes);
575ose_bundle ose_newBundleFromZeroedCBytes(int32_t nbytes, char *bytes);
576
577
578
579
589#define OSE_REGISTER_ADDRESS_LEN 3
590
591
592
593
629 const char * const address,
630 ose_bundle *reg,
631 const char **rest);
632
633#ifdef __cplusplus
634}
635#endif
636
637
638
639/* INLINE IN A RELEASE BUILD: ose_readSize.
640
641 They are the most called functions in the VM and do almost nothing, and a
642 call into another file cannot be inlined without link-time optimisation --
643 which a host built as several libraries cannot have across them. Measured
644 on one host's heaviest message path, seven of these inline took 20.7 to
645 15.7 us; the whole of LTO took it to 13.2.
646
647 The functions are still defined and exported, for anything that takes
648 their address or calls them from another language. A debug build calls
649 them, and gets their asserts. OSE_INLINE_ACCESSORS_OFF turns this off. */
650#if !defined(OSE_CONF_DEBUG) && !defined(OSE_INLINE_ACCESSORS_OFF)
651static inline int32_t ose_readSize_inline(ose_constbundle b)
652{ return ose_ntohl(*((const int32_t *)(ose_getBundlePtr(b) + OSE_CONTEXT_BUNDLE_SIZE_OFFSET))); }
653#define ose_readSize(b) ose_readSize_inline(b)
654#endif
655
656#endif
provides global definitions and types
void ose_copyBundle(ose_bundle src, ose_bundle dest)
Copy the topmost bundle element to a destination at the same level.
Definition ose_context.c:972
int32_t ose_spaceAvailable(ose_bundle bundle)
Returns the number of unused bytes in the bundle.
Definition ose_context.c:648
void ose_appendBundle(ose_bundle src, ose_bundle dest)
Append the contents of the topmost element of src to dest. Equivalent to.
Definition ose_context.c:1064
int32_t ose_init(ose_bundle bundle, int32_t size, const char *const address)
Initializes a newly created bundle with a context message.
Definition ose_context.c:412
void ose_replaceBundle(ose_bundle src, ose_bundle dest)
Replace the contents of dest with those of the topmost element of src. Equivalent to.
Definition ose_context.c:1139
ose_bundle ose_exit(ose_bundle bundle)
Exit a bundle context and move one level up.
Definition ose_context.c:733
int32_t ose_addressToRegister(ose_bundle osevm, const char *const address, ose_bundle *reg, const char **rest)
Split an address into a register and the rest of the address.
Definition ose_context.c:587
ose_bundle ose_enterBundleAtOffset(ose_bundle bundle, int32_t offset)
Enter a new bundle context.
Definition ose_context.c:695
void ose_context_set_flags(ose_bundle b, int32_t flags)
Read and write the flags word of a context message.
Definition ose_context.c:141
int32_t ose_getContextMessageOffset(ose_bundle bundle, const char *const address)
Returns the offset of the context message for a given address.
Definition ose_context.c:663
int32_t ose_pushContextMessage(ose_bundle bundle, int32_t size, const char *const address)
Pushes a new context message onto the current bundle.
Definition ose_context.c:479
void ose_context_set_changed(ose_bundle b)
The context's version: moved on by every change to its bundle's size, and never set back.
Definition ose_context.c:122
ose_bundle ose_newBundleFromZeroedCBytes(int32_t nbytes, char *bytes)
The same, for bytes the caller knows are all zero – from calloc, say – which are not written over: pa...
Definition ose_context.c:1183
int ose_addToSize(ose_bundle bundle, int32_t amt)
Add an amount to the size of a bundle. This function takes care of adjusting the size of the blob of ...
Definition ose_context.c:757
void ose_copyElemAtOffset(int32_t srcoffset, ose_bundle src, ose_bundle dest)
Append the element at srcoffset in src to dest.
Definition ose_context.c:922
ose_bundle ose_enter(ose_bundle bundle, const char *const address)
Enter a new bundle context.
Definition ose_context.c:708
ose_bundle ose_newBundleFromCBytes(int32_t nbytes, char *bytes)
Initialize a new bundle from an array of bytes.
Definition ose_context.c:1171
#define B(...)
Instantiate a top-level OSC bundle.
Definition ose_test_ctosc.h:339
Definition ose.h:400