Wednesday, January 5, 2022

Adding multiple of the same object in ObjectBox ToMany relationship

If you're using ObjectBox for handling your local data storage, it's possible you've run into the restriction that a single ToMany relationship can not contain multiple of the same object. For example, if you have two classes Pattern and Color:
@Entity
data class Color(var name: String) {
}

@Entity
data class Pattern(var name: String) {
	lateinit var colors : ToMany
}
then you may have the following colors:
+----+---------------+
| ID |   name        |
+----+---------------+
|  1 |   Blue        |
+----+---------------+
|  2 |   Yellow      |
+----+---------------+
But you cannot have a Pattern object with say, Blue, Yellow, Blue. One possible workaround is to add another Color Blue (with say, ID 3), but this can get ugly if you later change Blue to Purple and expect the Pattern to now be Purple, Yellow, Purple. One simple workaround I've found is to create a proxy class for the target entity. The proxy class will simply contain a ToOne relationship to the target entity type. You then change the ToMany relationship to point to the proxy class instead. So in our example above, we add a new ColorProxy class:
@Entity
data class ColorProxy() {
  lateinit var color : ToOne
}
and change the Pattern class to:
@Entity
data class Pattern(var name: String) {
	lateinit var colorProxies : ToMany
}
An extra Box will be required to hold the proxy objects and extra care must be taken to put() the proxy objects into their box, but it allows for a Pattern to contain multiple references to the same actual Color object. I know this is a bit of weird use case, but if you are reading this, hopefully this helped you out.

Thursday, August 3, 2017

Polymorphism and Aliasing

Someone recently asked me about strict aliasing, which is where two pointers of different types point to the same memory. The question came up whether you can have two pointers of sibling types point to each other. The answer is, not safely!

Consider the following:

   class A  
   {  
   public:  
     uint64_t mylong;  
   };  
   class B : public A  
   {  
   public:  
     uint32_t myint;  
     uint32_t myint2;  
   };  
   class C : public A  
   {  
   public:  
     uint64_t mylong2;  
     uint64_t mylong3;  
   };  
   int main(int argc, char** argv)  
   {  
     B* b = new B();  
     b->myint = 0;  
     C* c = (C*)b;  
     printf("%u %lu\n", b->myint, c->mylong3);  
   }  

Assuming an 8 byte alignment, we get the following sizes for these classes:
A: 8
B: 16
C: 24

When we alias our pointer c to b, we are taking a 24 byte long type and pointing at 16 bytes of memory! This means, when we access c->mylong3, we are accessing memory that has not been allocated yet!

Likewise, you should not create a new A type object, and then alias a B or C type pointer to it, as the extra memory for members other than mylong has not been allocated.

Thursday, October 31, 2013

Getting valgrind memcheck to work with uclibc

We recently built valgrind for uclibc through Angstrom and were dismayed to find that it would not find memory leaks, even ones we purposely leaked to test it with. Valgrind didn't complain of any errors, even with verbose debug output. Scratching our heads, we deep dived into the insanity that is valgrind and its virtual processor (which is actually incredibly fascinating and highly worth a look). After days of debugging, mainly through print statements, we found that the valgrind preload libraries (vgpreload_*-arm-linux.so) that actually contain the new malloc/free symbols were not being loaded.

It turns out that valgrind actually sets the LD_PRELOAD environment variable early in execution, before loading the executable that is to be analyzed. This should instruct the runtime link loader to load the libraries in LD_PRELOAD, which are the vgpreload ones. Unfortunately, if your uclibc is configured without LD_PRELOAD (like ours was), the loader will ignore LD_PRELOAD and valgrind won't know that the vgpreload libraries were never loaded and malloc was not replaced.

tl;dr uclibc must be configured with LD_PRELOAD in order for valgrind's memcheck to work.

Friday, March 16, 2012

Post do_package tasks and rm_work

Recently I ran into an issue surrounding a task that we needed to have run after the do_package task because some of its side effects muddied the ${D} directory with files we didn't want to be in our ipk package. We created a task do_create_foo that did the work we needed and set it to run after do_package. To our surprise, the stamp for the task was never created and the task tried to run every a recipe that depended on this one ran. This was especially bad since we use the rm_work class to save disk space, so when do_create_foo was run again, the ${D} was often missing entirely.

Some very long digging later, we discovered that the rm_work class was actually removing the stamp because it wasn't in its hard coded list or in the SSTATETASKS list. Since we didn't want to mess with making the task into an sstate task, we pulled a copy of rm_work.bbclass into our layer and added *do_create_foo* to the case statement in do_rm_work. Your mileage may vary, but hopefully this helps anyone out there with the case of the missing stamp!

Monday, January 30, 2012

Populating sysroot from non-standard paths

Your recipe is finally installing all of the correct files into their correct places during do_install, they are being packaged up properly, but something is still wrong. None of these files are ending up in the sysroot so other packages can make use of them. What's going on?!?

OE-Core only knows about a handful of paths that it should transfer over to the sysroot. In order to teach it about others, you need to define a function that does the populating and then add it to SYSROOT_PREPROCESS_FUNCS. Here's an example for recipe foo:

foo_populate_sysroot() {
sysroot_stage_dir ${D}/my/custom/path ${SYSROOT_DESTDIR}/my/custom/path
}
SYSROOT_PREPROCESS_FUNCS += "foo_populate_sysroot"

This will cause /my/custom/path to be exported to the sysroot and be available for other recipes to use. That's it, you're done! Note that the name of the function can be anything, the above name was used just for clarity.

Tuesday, October 4, 2011

The importance of base_prefix

Recently I started into converting our -native recipes from oe-classic into oe-core. First try I got a strange error from tar about the path not existing. The path it wanted looked crazy, something like /home/user/Angstrom/build/tmp-angstrom_2010_x-uclibc/work/armv7a-vfp-angstrom-linux-uclibceabi/mypackage-1.0-r0/image///home/user/Angstrom/build/tmp-angstrom_2010_x-uclibc/sysroots/mymachine. Debugging the scripts lead me into a maddening maze. The problem seemed to be emanating from the sstate creation tasks.

It turns out that we were not respecting the ${base_prefix} variable when doing our install. The recipe we were using installs into a non-standard location, so we were installing into something like ${D}/opt/custom-place/ but native recipes actually set the base_prefix to a really strange value like /home/user/Angstrom/build/tmp-angstrom_2010_x-uclibc/sysroots/mymachine. For reference, in normal embedded builds, ${base_prefix} is an empty string.

The fix was simple. Install instead to ${D}${base_prefix}/opt/custom-place/ which installs to the same place it always had during embedded builds, and the long path that tar was looking for during -native builds of the recipe.

Happy building!

Friday, September 30, 2011

What is this blog about exactly?

I'm glad you asked! This blog will be all about my challenges and solutions in creating Embedded Linux platforms, and my musings on computer technology. When I first joined up as a firmware engineer, I was terrified. How could I ever work effectively on such complicated systems? It has been a wild ride and everyday brings new and exciting problems. I can't wait to share them all with you.