Trains traditionally operate on signalling blocks: a section between two signals is a block, a block is occupied if any part of a train is inside of it, if it's occupied any signals leading into the block are red. This can be decided entirely locally (as in: local to the block). When a wheel sensor detects a wheel entering the block, the block is occupied, signals switch to red and the number of wheels is counted. As soon as another wheel sensor counts an equal number of wheels exiting the block the block is free and signals switch to green. You need a wire along the block to communicate this, but from a safety perspective there is no need for global communication.
Modernization efforts focus on trains broadcasting position and speed so trains can travel closer together and still maintain a safe stopping distance, but that's again possible locally.
Operating switches is where it gets trickier. Some rail operators maintain the possibility to operate them locally, but that requires either stopping the train at each switch you want to change, or to deploy lots of people into the field to do it on schedule