In my case, I found the culprit and also found how to reproduce the issue.
The culprit was that my servlet opened files by using the Scanner class and neglected to use Scanner.close after reading the files. The files being opened were ones in WEB-INF/classes and hence tomcat's undeploy operation couldn't delete the contents of the WEB-INF/classes folder.
Here's the scenario to reproduce the issue (before fixing it by adding calls to Scanner.close):
After adding Scanner.close invocation, the above scenario no longer has any issues.