There's one more thing you have to worry about. Let's say the timing resolution is 10 ms and you want a 20 ms timeout.
Are you always going to get exactly 20 milliseconds worth of delay from the time that you issue the delay() call to the time that the function call returns?
Absolutely not.
There are two good reasons why. The first is fairly simple: when you block, you're taken off the running queue. This means that another thread at your priority may now be using the CPU. When your 20 milliseconds have expired, you'll be placed at the end of the READY queue for that priority so you'll be at the mercy of whatever thread happens to be running. This also applies to interrupt handlers running or higher-priority threads running—just because you are READY doesn't mean that you're consuming the CPU.
The second reason is a bit more subtle. The following diagram will help explain why:
The problem is that your request is asynchronous to the clock source. You have no way to synchronize the hardware clock with your request. Therefore, you'll get from just over 20 milliseconds to just under 30 milliseconds worth of delay, depending on where in the hardware's clock period you started your request.