Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
11 KiB

  1. /*
  2. * serial.c - Access serialization routines module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "init.h"
  9. /* Types
  10. ********/
  11. /* process information */
  12. typedef struct _processinfo
  13. {
  14. HANDLE hModule;
  15. }
  16. PROCESSINFO;
  17. DECLARE_STANDARD_TYPES(PROCESSINFO);
  18. #ifdef DEBUG
  19. /* debug flags */
  20. typedef enum _serialdebugflags
  21. {
  22. SERIAL_DFL_BREAK_ON_PROCESS_ATTACH = 0x0001,
  23. SERIAL_DFL_BREAK_ON_THREAD_ATTACH = 0x0002,
  24. ALL_SERIAL_DFLAGS = (SERIAL_DFL_BREAK_ON_PROCESS_ATTACH |
  25. SERIAL_DFL_BREAK_ON_THREAD_ATTACH)
  26. }
  27. SERIALDEBUGFLAGS;
  28. #endif /* DEBUG */
  29. /* Module Variables
  30. *******************/
  31. #pragma data_seg(DATA_SEG_PER_INSTANCE)
  32. /* critical section used for access serialization */
  33. PRIVATE_DATA NONREENTRANTCRITICALSECTION s_nrcs =
  34. {
  35. { 0 },
  36. #ifdef DEBUG
  37. INVALID_THREAD_ID,
  38. #endif /* DEBUG */
  39. FALSE
  40. };
  41. /* information about current process */
  42. /*
  43. * Initialize s_pi so it is actually put in the .instanc section instead of the
  44. * .bss section.
  45. */
  46. PRIVATE_DATA PROCESSINFO s_pi =
  47. {
  48. NULL
  49. };
  50. #pragma data_seg()
  51. #ifdef DEBUG
  52. #pragma data_seg(DATA_SEG_SHARED)
  53. /* debug flags */
  54. PRIVATE_DATA DWORD s_dwSerialModuleFlags = 0;
  55. #pragma data_seg(DATA_SEG_READ_ONLY)
  56. /* .ini file switch descriptions */
  57. PRIVATE_DATA CBOOLINISWITCH s_cbisBreakOnProcessAttach =
  58. {
  59. IST_BOOL,
  60. "BreakOnProcessAttach",
  61. &s_dwSerialModuleFlags,
  62. SERIAL_DFL_BREAK_ON_PROCESS_ATTACH
  63. };
  64. PRIVATE_DATA CBOOLINISWITCH s_cbisBreakOnThreadAttach =
  65. {
  66. IST_BOOL,
  67. "BreakOnThreadAttach",
  68. &s_dwSerialModuleFlags,
  69. SERIAL_DFL_BREAK_ON_THREAD_ATTACH
  70. };
  71. PRIVATE_DATA const PCVOID s_rgcpcvisSerialModule[] =
  72. {
  73. &s_cbisBreakOnProcessAttach,
  74. &s_cbisBreakOnThreadAttach
  75. };
  76. #pragma data_seg()
  77. #endif /* DEBUG */
  78. /***************************** Private Functions *****************************/
  79. /* Module Prototypes
  80. ********************/
  81. #ifdef DEBUG
  82. PRIVATE_CODE BOOL IsValidPCSERIALCONTROL(PCSERIALCONTROL);
  83. PRIVATE_CODE BOOL IsValidPCPROCESSINFO(PCPROCESSINFO);
  84. PRIVATE_CODE BOOL IsValidPCCRITICAL_SECTION(PCCRITICAL_SECTION);
  85. PRIVATE_CODE BOOL IsValidThreadId(DWORD);
  86. PRIVATE_CODE BOOL IsValidPCNONREENTRANTCRITICALSECTION(PCNONREENTRANTCRITICALSECTION);
  87. #endif
  88. #ifdef DEBUG
  89. PRIVATE_CODE BOOL IsValidPCSERIALCONTROL(PCSERIALCONTROL pcserctrl)
  90. {
  91. return(IS_VALID_READ_PTR(pcserctrl, CSERIALCONTROL) &&
  92. (! pcserctrl->AttachProcess ||
  93. IS_VALID_CODE_PTR(pcserctrl->AttachProcess, AttachProcess)) &&
  94. (! pcserctrl->DetachProcess ||
  95. IS_VALID_CODE_PTR(pcserctrl->DetachProcess, DetachProcess)) &&
  96. (! pcserctrl->AttachThread ||
  97. IS_VALID_CODE_PTR(pcserctrl->AttachThread, AttachThread)) &&
  98. (! pcserctrl->DetachThread||
  99. IS_VALID_CODE_PTR(pcserctrl->DetachThread, DetachThread)));
  100. }
  101. PRIVATE_CODE BOOL IsValidPCPROCESSINFO(PCPROCESSINFO pcpi)
  102. {
  103. return(IS_VALID_READ_PTR(pcpi, CPROCESSINFO) &&
  104. IS_VALID_HANDLE(pcpi->hModule, MODULE));
  105. }
  106. PRIVATE_CODE BOOL IsValidPCCRITICAL_SECTION(PCCRITICAL_SECTION pccritsec)
  107. {
  108. return(IS_VALID_READ_PTR(pccritsec, CCRITICAL_SECTION));
  109. }
  110. PRIVATE_CODE BOOL IsValidThreadId(DWORD dwThreadId)
  111. {
  112. return(dwThreadId != INVALID_THREAD_ID);
  113. }
  114. PRIVATE_CODE BOOL IsValidPCNONREENTRANTCRITICALSECTION(
  115. PCNONREENTRANTCRITICALSECTION pcnrcs)
  116. {
  117. /* bEntered may be any value. */
  118. return(IS_VALID_READ_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION) &&
  119. IS_VALID_STRUCT_PTR(&(pcnrcs->critsec), CCRITICAL_SECTION) &&
  120. EVAL(pcnrcs->dwOwnerThread == INVALID_THREAD_ID ||
  121. IsValidThreadId(pcnrcs->dwOwnerThread)));
  122. }
  123. #endif
  124. /****************************** Public Functions *****************************/
  125. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  126. #ifdef DEBUG
  127. PUBLIC_CODE BOOL SetSerialModuleIniSwitches(void)
  128. {
  129. BOOL bResult;
  130. bResult = SetIniSwitches(s_rgcpcvisSerialModule,
  131. ARRAY_ELEMENTS(s_rgcpcvisSerialModule));
  132. ASSERT(FLAGS_ARE_VALID(s_dwSerialModuleFlags, ALL_SERIAL_DFLAGS));
  133. return(bResult);
  134. }
  135. #endif
  136. PUBLIC_CODE BOOL AttachProcess(HMODULE hmod)
  137. {
  138. BOOL bResult;
  139. ASSERT(IS_VALID_HANDLE(hmod, MODULE));
  140. InitializeNonReentrantCriticalSection(&s_nrcs);
  141. bResult = EnterNonReentrantCriticalSection(&s_nrcs);
  142. if (bResult)
  143. {
  144. #ifdef DEBUG
  145. ASSERT(SetAllIniSwitches());
  146. TRACE_OUT(("AttachProcess(): Called for module %#lx.",
  147. hmod));
  148. if (IS_FLAG_SET(s_dwSerialModuleFlags, SERIAL_DFL_BREAK_ON_PROCESS_ATTACH))
  149. {
  150. WARNING_OUT(("AttachProcess(): Breaking on process attach, as requested."));
  151. #ifndef MAINWIN
  152. DebugBreak();
  153. #endif
  154. }
  155. #endif /* DEBUG */
  156. s_pi.hModule = hmod;
  157. ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
  158. if (g_cserctrl.AttachProcess)
  159. bResult = g_cserctrl.AttachProcess(hmod);
  160. LeaveNonReentrantCriticalSection(&s_nrcs);
  161. }
  162. return(bResult);
  163. }
  164. PUBLIC_CODE BOOL DetachProcess(HMODULE hmod)
  165. {
  166. BOOL bResult;
  167. ASSERT(IS_VALID_HANDLE(hmod, MODULE));
  168. bResult = EnterNonReentrantCriticalSection(&s_nrcs);
  169. if (bResult)
  170. {
  171. ASSERT(hmod == s_pi.hModule);
  172. TRACE_OUT(("DetachProcess(): Called for module %#lx.",
  173. hmod));
  174. ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
  175. if (g_cserctrl.DetachProcess)
  176. bResult = g_cserctrl.DetachProcess(hmod);
  177. LeaveNonReentrantCriticalSection(&s_nrcs);
  178. DeleteNonReentrantCriticalSection(&s_nrcs);
  179. }
  180. return(bResult);
  181. }
  182. PUBLIC_CODE BOOL AttachThread(HMODULE hmod)
  183. {
  184. BOOL bResult;
  185. ASSERT(IS_VALID_HANDLE(hmod, MODULE));
  186. bResult = EnterNonReentrantCriticalSection(&s_nrcs);
  187. if (bResult)
  188. {
  189. #ifdef DEBUG
  190. ASSERT(SetAllIniSwitches());
  191. TRACE_OUT(("AttachThread() called for module %#lx, thread ID %#lx.",
  192. hmod,
  193. GetCurrentThreadId()));
  194. if (IS_FLAG_SET(s_dwSerialModuleFlags, SERIAL_DFL_BREAK_ON_THREAD_ATTACH))
  195. {
  196. WARNING_OUT(("AttachThread(): Breaking on thread attach, as requested."));
  197. #ifndef MAINWIN
  198. DebugBreak();
  199. #endif
  200. }
  201. #endif
  202. ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
  203. if (g_cserctrl.AttachThread)
  204. bResult = g_cserctrl.AttachThread(hmod);
  205. else
  206. bResult = TRUE;
  207. LeaveNonReentrantCriticalSection(&s_nrcs);
  208. }
  209. return(bResult);
  210. }
  211. PUBLIC_CODE BOOL DetachThread(HMODULE hmod)
  212. {
  213. BOOL bResult;
  214. ASSERT(IS_VALID_HANDLE(hmod, MODULE));
  215. bResult = EnterNonReentrantCriticalSection(&s_nrcs);
  216. if (bResult)
  217. {
  218. TRACE_OUT(("DetachThread() called for module %#lx, thread ID %#lx.",
  219. hmod,
  220. GetCurrentThreadId()));
  221. ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
  222. if (g_cserctrl.DetachThread)
  223. bResult = g_cserctrl.DetachThread(hmod);
  224. else
  225. bResult = TRUE;
  226. LeaveNonReentrantCriticalSection(&s_nrcs);
  227. }
  228. return(bResult);
  229. }
  230. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */
  231. PUBLIC_CODE void InitializeNonReentrantCriticalSection(
  232. PNONREENTRANTCRITICALSECTION pnrcs)
  233. {
  234. ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
  235. InitializeCriticalSection(&(pnrcs->critsec));
  236. pnrcs->bEntered = FALSE;
  237. #ifdef DEBUG
  238. pnrcs->dwOwnerThread = INVALID_THREAD_ID;
  239. #endif
  240. return;
  241. }
  242. PUBLIC_CODE BOOL EnterNonReentrantCriticalSection(
  243. PNONREENTRANTCRITICALSECTION pnrcs)
  244. {
  245. BOOL bEntered;
  246. #ifdef DEBUG
  247. BOOL bBlocked;
  248. ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
  249. /* Is the critical section already owned by another thread? */
  250. /* Use pnrcs->bEntered and pnrcs->dwOwnerThread unprotected here. */
  251. bBlocked = (pnrcs->bEntered &&
  252. GetCurrentThreadId() != pnrcs->dwOwnerThread);
  253. if (bBlocked)
  254. TRACE_OUT(("EnterNonReentrantCriticalSection(): Blocking thread %lx. Critical section is already owned by thread %#lx.",
  255. GetCurrentThreadId(),
  256. pnrcs->dwOwnerThread));
  257. #endif
  258. EnterCriticalSection(&(pnrcs->critsec));
  259. bEntered = (! pnrcs->bEntered);
  260. if (bEntered)
  261. {
  262. pnrcs->bEntered = TRUE;
  263. #ifdef DEBUG
  264. pnrcs->dwOwnerThread = GetCurrentThreadId();
  265. if (bBlocked)
  266. TRACE_OUT(("EnterNonReentrantCriticalSection(): Unblocking thread %lx. Critical section is now owned by this thread.",
  267. pnrcs->dwOwnerThread));
  268. #endif
  269. }
  270. else
  271. {
  272. LeaveCriticalSection(&(pnrcs->critsec));
  273. ERROR_OUT(("EnterNonReentrantCriticalSection(): Thread %#lx attempted to reenter non-reentrant code.",
  274. GetCurrentThreadId()));
  275. }
  276. return(bEntered);
  277. }
  278. PUBLIC_CODE void LeaveNonReentrantCriticalSection(
  279. PNONREENTRANTCRITICALSECTION pnrcs)
  280. {
  281. ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
  282. if (EVAL(pnrcs->bEntered))
  283. {
  284. pnrcs->bEntered = FALSE;
  285. #ifdef DEBUG
  286. pnrcs->dwOwnerThread = INVALID_THREAD_ID;
  287. #endif
  288. LeaveCriticalSection(&(pnrcs->critsec));
  289. }
  290. return;
  291. }
  292. PUBLIC_CODE void DeleteNonReentrantCriticalSection(
  293. PNONREENTRANTCRITICALSECTION pnrcs)
  294. {
  295. ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
  296. ASSERT(! pnrcs->bEntered);
  297. ASSERT(pnrcs->dwOwnerThread == INVALID_THREAD_ID);
  298. DeleteCriticalSection(&(pnrcs->critsec));
  299. return;
  300. }
  301. #ifdef DEBUG
  302. PUBLIC_CODE BOOL NonReentrantCriticalSectionIsOwned(
  303. PCNONREENTRANTCRITICALSECTION pcnrcs)
  304. {
  305. ASSERT(IS_VALID_STRUCT_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION));
  306. return(pcnrcs->bEntered);
  307. }
  308. PUBLIC_CODE DWORD GetNonReentrantCriticalSectionOwner(
  309. PCNONREENTRANTCRITICALSECTION pcnrcs)
  310. {
  311. ASSERT(IS_VALID_STRUCT_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION));
  312. return(pcnrcs->dwOwnerThread);
  313. }
  314. #endif
  315. PUBLIC_CODE BOOL BeginExclusiveAccess(void)
  316. {
  317. return(EnterNonReentrantCriticalSection(&s_nrcs));
  318. }
  319. PUBLIC_CODE void EndExclusiveAccess(void)
  320. {
  321. LeaveNonReentrantCriticalSection(&s_nrcs);
  322. return;
  323. }
  324. #ifdef DEBUG
  325. PUBLIC_CODE BOOL AccessIsExclusive(void)
  326. {
  327. return(NonReentrantCriticalSectionIsOwned(&s_nrcs) &&
  328. GetNonReentrantCriticalSectionOwner(&s_nrcs) == GetCurrentThreadId());
  329. }
  330. #endif /* DEBUG */
  331. PUBLIC_CODE HMODULE GetThisModulesHandle(void)
  332. {
  333. ASSERT(IS_VALID_STRUCT_PTR((PCPROCESSINFO)&s_pi, CPROCESSINFO));
  334. return(s_pi.hModule);
  335. }