libose
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#ifdef OSE_CONF_CONTEXT_CACHE_SIZE
59#define OSE_CONTEXT_CACHE_SIZE OSE_CONF_CONTEXT_CACHE_SIZE
60#else
61#define OSE_CONTEXT_CACHE_SIZE 64
62#endif
63#define OSE_CONTEXT_NUM_CACHE_ITEMS 3
64#define OSE_CONTEXT_CACHE_TYPETAG_STRLEN 8
65
66#define OSE_CONTEXT_BUNDLE_SIZE_OFFSET -4
67#define OSE_CONTEXT_TOTAL_SIZE_OFFSET -8
68#define OSE_CONTEXT_PARENT_BUNDLE_OFFSET_OFFSET -12
69#define OSE_CONTEXT_STATUS_OFFSET -16
70#define OSE_CONTEXT_MEMUSAGE_OFFSET -20
71#define OSE_CONTEXT_CHANGED_OFFSET -24
72/* The context message's typetags are ",bbbiiiiibb": a cache blob, then two
73 * blobs that are unused. An empty blob is exactly the four bytes of its own
74 * size word, and an int32 is four bytes too, so spelling the second as `i`
75 * changes the typetag string and nothing else -- same offsets, same
76 * OSE_CONTEXT_BUNDLE_OFFSET, same padded typetag length. -32 remains unused.
77 *
78 * libose stores this word and does not read it. No bit is named here, which
79 * is the split ose_vm.h keeps for declarations: ose manipulates, and its
80 * clients interpret. A register that must not travel, or one destroyed when
81 * its machine goes idle, are facts about saving and driving, and libose does
82 * neither, so it has no way to be right about them. Whichever client saves
83 * and drives names the bits. */
84#define OSE_CONTEXT_FLAGS_OFFSET -28
85#define OSE_CONTEXT_CACHE_OFFSET -(36 + OSE_CONTEXT_CACHE_SIZE)
86
87void ose_context_set_status(ose_bundle b, int32_t s);
88int32_t ose_context_get_status(ose_bundle b);
89void ose_context_set_changed(ose_bundle b);
90void ose_context_reset_changed(ose_bundle b);
91int32_t ose_context_get_changed(ose_bundle b);
102void ose_context_set_flags(ose_bundle b, int32_t flags);
103int32_t ose_context_get_flags(ose_bundle b);
104/* void ose_context_set_cachefns(ose_bundle B, */
105/* int32_t (*getFirstOffsetForMatch)(ose_bundle, */
106/* const char * const, */
107/* void**), */
108/* void *userdata); */
109void ose_context_cache_set(ose_bundle B,
110 int32_t o,
111 void *i);
112void ose_context_cache_setGetFirstOffsetForMatchFn(ose_bundle B,
113 int32_t (*getFirstOffsetForMatch)(ose_bundle,
114 const char * const,
115 void**));
116void ose_context_cache_setUserdata(ose_bundle B,
117 void *userdata);
118
119/* The pair to ose_context_cache_setUserdata(). A cache owner that keeps a
120 sized allocation here needs to read the pointer back in order to report
121 how much of it is in use. */
122void *ose_context_cache_getUserdata(ose_bundle B);
123void ose_context_cache_setTypeBundle(ose_bundle B,
124 ose_bundle tx);
125int32_t ose_context_getFirstOffsetForMatch(ose_bundle B,
126 const char * const address);
127ose_bundle ose_getTypeBundle(ose_constbundle bundle);
128
129#ifdef OSE_MEMPROFILE
130int32_t ose_get_memusage(ose_bundle b);
131void ose_reset_memusage(ose_bundle b);
132#else
133#define ose_get_memusage(b) do{}while(0)
134#define ose_reset_memusage(b) do{}while(0)
135#endif
136
137
138
162#define OSE_CONTEXT_MESSAGE_TYPETAGS ",bbiiiiiibb"
163
167#define OSE_CONTEXT_MESSAGE_TYPETAGS_PLEN 12
168
169#define OSE_CONTEXT_BUNDLE_OFFSET \
170 (4 /* size */ \
171 + 4 /* padded address len */ \
172 + 12 /* padded typetag str */ \
173 + 4 + OSE_CONTEXT_CACHE_SIZE /* blob - cache */ \
174 + 4 /* blob - unused */ \
175 + 4 /* int - flags */ \
176 + 4 /* int - changed */ \
177 + 4 /* int - memusage */ \
178 + 4 /* int - status */ \
179 + 4 /* int - offset to bundle */ \
180 + 4 /* int - total size */ \
181 + 4) /* blob size */
182
183
184
185
186int32_t ose_readSize(ose_constbundle bundle);
187
188
189
190
194#define OSE_CONTEXT_MESSAGE_OVERHEAD \
195 (OSE_CONTEXT_BUNDLE_OFFSET \
196 + OSE_BUNDLE_HEADER_LEN /* bundle header */ \
197 + 4) /* blob size */
198
199
200
201
205#define OSE_CONTEXT_STATUS_MESSAGE_SIZE 16
206
207
208
209
213#define OSE_CONTEXT_TYPE_MESSAGE_SIZE 1024
214
215
216
217
221#define OSE_CONTEXT_MAX_OVERHEAD \
222 ((OSE_CONTEXT_ALIGNMENT) \
223 + OSE_BUNDLE_HEADER_LEN \
224 + OSE_CONTEXT_MESSAGE_OVERHEAD \
225 + OSE_CONTEXT_STATUS_MESSAGE_SIZE \
226 + OSE_CONTEXT_MESSAGE_OVERHEAD \
227 + OSE_CONTEXT_MESSAGE_OVERHEAD \
228 + OSE_CONTEXT_TYPE_MESSAGE_SIZE)
229
230
231
232
242int32_t ose_init(ose_bundle bundle,
243 int32_t size,
244 const char * const address);
245
246
247
248
249
260 int32_t size,
261 const char * const address);
262void ose_dropContextMessage(ose_bundle bundle);
263
264/* How many times the shape of any context has changed: a context message
265 * made or dropped, or a bundle made over raw bytes.
266 *
267 * Something that remembers where things are inside registers -- an offset
268 * into a register, or the register itself -- can keep this and trust what it
269 * remembers only while it has not moved. A register made or dropped moves
270 * every register after it, and a machine built again in the same bytes is a
271 * different machine at the same address, which nothing else in a bundle
272 * says. Changes to what a register holds are not counted here; that is each
273 * register's own changed flag. */
274extern uint32_t ose_context_generation;
275
276
277
278
279
286int32_t ose_spaceAvailable(ose_constbundle bundle);
287
288
289
290
299 const char * const address);
300
301
302
303
304
314 int32_t offset);
315
316
317
318
332 const char * const address);
333
334
335
336
337
344ose_bundle ose_exit(ose_constbundle bundle);
345
346
347
348
349
375int ose_addToSize(ose_bundle bundle, int32_t amt);
376int ose_incSize(ose_bundle bundle, int32_t amt);
377int ose_decSize(ose_bundle bundle, int32_t amt);
378
379
380
381
382
390/* void ose_copyBundleElemToDest(ose_bundle src, ose_bundle dest); */
391
392
393
394
395
403/* void ose_copyBundleElemToDestAddr(ose_bundle src, const char * const dest_addr); */
404
405
406
407
408
416/* void ose_moveBundleElemToDest(ose_bundle src, ose_bundle dest); */
417
418
419
420
421
429/* void ose_moveBundleElemToDestAddr(ose_bundle src, */
430/* const char * const dest_addr); */
431
432
433
434
435
446/* void ose_replaceBundleElemInDest(ose_bundle src, ose_bundle dest); */
447
448
449
450
451
462/* void ose_replaceBundleElemInDestAddr(ose_bundle src, */
463/* const char * const dest_addr); */
464
465
466
467
468
475void ose_copyBundle(ose_constbundle src, ose_bundle dest);
476
477
478
479
480
494
495
496
497
522void ose_copyElemAtOffset(int32_t srcoffset,
523 ose_constbundle src,
524 ose_bundle dest);
525#define ose_copyElem(src, dest) \
526 ose_copyElemAtOffset(ose_getLastBundleElemOffset(src), \
527 src, dest)
528#define ose_moveElem(src, dest) \
529 { \
530 int32_t o = ose_getLastBundleElemOffset(src); \
531 ose_copyElemAtOffset(o, src, dest); \
532 ose_dropAtOffset(src, o); \
533 }
534
535
536
537
538int32_t ose_routeElemAtOffset(int32_t srcoffset,
539 ose_constbundle src,
540 int32_t prefixlen,
541 ose_bundle dest);
542
543
544
545
546
558ose_bundle ose_newBundleFromCBytes(int32_t nbytes, char *bytes);
559
560
561
562
572#define OSE_REGISTER_ADDRESS_LEN 3
573
574
575
576
612 const char * const address,
613 ose_bundle *reg,
614 const char **rest);
615
616#ifdef __cplusplus
617}
618#endif
619
620
621
622/* INLINE IN A RELEASE BUILD: ose_readSize.
623
624 They are the most called functions in the VM and do almost nothing, and a
625 call into another file cannot be inlined without link-time optimisation --
626 which a host built as several libraries cannot have across them. Measured
627 on one host's heaviest message path, seven of these inline took 20.7 to
628 15.7 us; the whole of LTO took it to 13.2.
629
630 The functions are still defined and exported, for anything that takes
631 their address or calls them from another language. A debug build calls
632 them, and gets their asserts. OSE_INLINE_ACCESSORS_OFF turns this off. */
633#if !defined(OSE_CONF_DEBUG) && !defined(OSE_INLINE_ACCESSORS_OFF)
634static inline int32_t ose_readSize_inline(ose_constbundle b)
635{ return ose_ntohl(*((const int32_t *)(ose_getBundlePtr(b) + OSE_CONTEXT_BUNDLE_SIZE_OFFSET))); }
636#define ose_readSize(b) ose_readSize_inline(b)
637#endif
638
639#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:951
int32_t ose_spaceAvailable(ose_bundle bundle)
Returns the number of unused bytes in the bundle.
Definition ose_context.c:627
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:1043
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:396
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:1118
ose_bundle ose_exit(ose_bundle bundle)
Exit a bundle context and move one level up.
Definition ose_context.c:712
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:565
ose_bundle ose_enterBundleAtOffset(ose_bundle bundle, int32_t offset)
Enter a new bundle context.
Definition ose_context.c:674
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:125
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:642
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:467
uint32_t ose_context_generation
Make a new context bundle (a register) inside bundle.
Definition ose_context.c:465
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:736
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:901
ose_bundle ose_enter(ose_bundle bundle, const char *const address)
Enter a new bundle context.
Definition ose_context.c:687
ose_bundle ose_newBundleFromCBytes(int32_t nbytes, char *bytes)
Initialize a new bundle from an array of bytes.
Definition ose_context.c:1147
#define B(...)
Instantiate a top-level OSC bundle.
Definition ose_test_ctosc.h:339
Definition ose.h:374