Techniques for Building Timing-Predictable Embedded Systems