Giter Club home page Giter Club logo

c-hotreload's Introduction

Hot Reloading but in C

Hot reloading is a technique used to reload code while the program is running. This is especially useful for anything graphical, as you can see the changes you make in real time. This is usually done more easily in interpreted languages like Python or JavaScript, but it can also be done in C. This repository is a simple example of how to do hot reloading in C, which handles changes in the layout of the state struct.

Inspiration

This is inspired by tsoding's video Hot Code Reloading in C where he implemented hot reloading in his music visualizer. I wanted to take this idea further and handle changes in the layout of the state struct, which is a common problem when doing hot reloading.

How it works

Code reloading

The idea is that we offload all the actual logic of the program into a shared library, and then load that library at runtime. We can make a small launcher program that loads the library, and then we can compile the library separately. This way, we can compile the library and the launcher separately, and then we can reload the library without having to recompile the currently running program.

On unix-like systems, we can use dlopen to load a shared library at runtime. We can then use dlsym to get the address of the functions in the library, and call it just like any other function. When we want to reload the libary we can use dlclose to unload the library, and then repeat the process to load the new version of the library. On Windows, we can use LoadLibrary, FreeLibrary and GetProcAddress to do the same thing, but I won't implement this in this repository.

State Reloading

To make hot reloading more useful, we can preserve the state of the program across reloads. This can be easily done by have a struct that holds all the state of the program, and then passing a pointer to that struct across reloads. We can allocate this on the heap, as the heap is shared between the library and the launcher.

However we need to be careful with this, as we can expect the layout of the struct to change between reloads. We need to store extra runtime type information (RTTI) in the struct, so that we can check which parts of the new struct are similar to the old struct. We can then copy the data from the old struct to the new struct, and then free the old struct. This is where X macros come in handy, as we can easily generate the runtime type information. We can use the preprocessor to generate the RTTI, offsetof and sizeof and the # operator to generate the name, type, offset and size of each field in the struct.

However we can't just store the RTTI in a static variable because we will lose it across reloads. Instead we can embed it in state struct itself and copy all the entries during initialization. However we run into a bit of a problem. The RTTI contains string literals, which would need extra heap allocations. This would make our RTTI very fragmented, with lots of small allocations. But we know the size of all of this at compile time, and we can compute it. That means we can just allocate a single block of memory or an arena for the state and the RTTI, and copy everything there. This makes the RTTI very cache friendly, and easy to free when we are done with it.

Putting this all together we can add two lifecycle hooks to the library, plug_pre_reload and plug_post_reload. The plug_pre_reload function is called before the library is reloaded, and the plug_post_reload function is from the new library after it is loaded. This way we can free the old state and merge the two states together.

During plug_pre_reload we have to return a pointer to the old state so we can pass it over to the new library during plug_post_reload and merge the two states together. For simplicity, I chose not to use a hash table or a more complex data structure to store the RTTI. Instead I just used a linear search to find the corresponding field in the new struct. This is fine since the number of fields in the state struct is usually reasonably small and hot reloading is only used during development. While merging the two states, we first allocate a new arena and initialize the new state. Then we loop over each field of the new state, and search for the corresponding field in the old state, with the same name, type and size. If one exists, then we can copy the data to the new state. If we can't find a corresponding field, then we can just leave it as is. This way we can preserve the state across reloads, and only have to reinitialize the fields that have changed. Finally we can free the old arena.

For a production build we can just statically link main.c and plug.c and use the preprocessor to conditionally enable the parts that are only used for hotreloading. This way we can have a single standalone binary without any of the hot reloading code.

c-hotreload's People

Contributors

markos-th09 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.