I've taken a look at the 357 reloading code. Apart from a few events that can be specified in animations, much of the timing appears to be hard-coded. Ideally you'd want the code to react to the end of an animation, but I don't know enough about the HL engine to say whether that's possible.
DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope );, so the actual 'ammo transfer' happens after 2 seconds. Apparently that's when you can fire the weapon again, even if the reload animation hasn't finished yet.
DefaultReload also contains the line
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;, which causes
CPython::WeaponIdle to pick a new idle animation after 3 seconds, regardless of whether the reload animation has finished.
CPython::WeaponIdle also contains hard-coded durations for each of the idle/fidget animations.