3c08885de7fe0446df7f91dc3007bbb56c358f2c
[reactos.git] / reactos / ntoskrnl / include / internal / ex.h
1 #pragma once
2
3 /* GLOBAL VARIABLES *********************************************************/
4
5 extern TIME_ZONE_INFORMATION ExpTimeZoneInfo;
6 extern LARGE_INTEGER ExpTimeZoneBias;
7 extern ULONG ExpTimeZoneId;
8 extern ULONG ExpTickCountMultiplier;
9 extern ULONG ExpLastTimeZoneBias;
10 extern POBJECT_TYPE ExEventPairObjectType;
11 extern POBJECT_TYPE _ExEventObjectType, _ExSemaphoreObjectType;
12 extern FAST_MUTEX ExpEnvironmentLock;
13 extern ERESOURCE ExpFirmwareTableResource;
14 extern LIST_ENTRY ExpFirmwareTableProviderListHead;
15 extern BOOLEAN ExpIsWinPEMode;
16 extern LIST_ENTRY ExpSystemResourcesList;
17 extern ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
18 extern ULONG ExpUnicodeCaseTableDataOffset;
19 extern PVOID ExpNlsSectionPointer;
20 extern ULONG NtGlobalFlag;
21 extern UNICODE_STRING NtSystemRoot;
22 extern ULONG ExpInitializationPhase;
23 extern ULONG ExpAltTimeZoneBias;
24 extern LIST_ENTRY ExSystemLookasideListHead;
25 extern PCALLBACK_OBJECT PowerStateCallback;
26 extern LIST_ENTRY ExPoolLookasideListHead;
27 extern LIST_ENTRY ExpNonPagedLookasideListHead;
28 extern LIST_ENTRY ExpPagedLookasideListHead;
29 extern KSPIN_LOCK ExpNonPagedLookasideListLock;
30 extern KSPIN_LOCK ExpPagedLookasideListLock;
31
32 /*
33 * NT/Cm Version Info variables
34 */
35 extern ULONG NtMajorVersion;
36 extern ULONG NtMinorVersion;
37 extern ULONG NtBuildNumber;
38 extern ULONG CmNtSpBuildNumber;
39 extern ULONG CmNtCSDVersion;
40 extern ULONG CmNtCSDReleaseType;
41 extern UNICODE_STRING CmVersionString;
42 extern UNICODE_STRING CmCSDVersionString;
43 extern CHAR NtBuildLab[];
44
45 // #ifdef _WINKD_
46 /*
47 * WinDBG Debugger Worker State Machine data (see dbgctrl.c)
48 */
49 typedef enum _WINKD_WORKER_STATE
50 {
51 WinKdWorkerReady = 0,
52 WinKdWorkerStart,
53 WinKdWorkerInitialized
54 } WINKD_WORKER_STATE;
55
56 extern WORK_QUEUE_ITEM ExpDebuggerWorkItem;
57 extern WINKD_WORKER_STATE ExpDebuggerWork;
58 extern PEPROCESS ExpDebuggerProcessAttach;
59 extern PEPROCESS ExpDebuggerProcessKill;
60 extern ULONG_PTR ExpDebuggerPageIn;
61 VOID NTAPI ExpDebuggerWorker(IN PVOID Context);
62 // #endif /* _WINKD_ */
63
64 #ifdef _WIN64
65 #define HANDLE_LOW_BITS (PAGE_SHIFT - 4)
66 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 3)
67 #else
68 #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
69 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
70 #endif
71 #define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - 31)
72
73 typedef union _EXHANDLE
74 {
75 struct
76 {
77 ULONG_PTR TagBits:2;
78 ULONG_PTR Index:29;
79 };
80 struct
81 {
82 ULONG_PTR TagBits2:2;
83 ULONG_PTR LowIndex:HANDLE_LOW_BITS;
84 ULONG_PTR MidIndex:HANDLE_HIGH_BITS;
85 ULONG_PTR HighIndex:HANDLE_HIGH_BITS;
86 ULONG_PTR KernelFlag:KERNEL_FLAG_BITS;
87 };
88 HANDLE GenericHandleOverlay;
89 ULONG_PTR Value;
90 } EXHANDLE, *PEXHANDLE;
91
92 typedef struct _ETIMER
93 {
94 KTIMER KeTimer;
95 KAPC TimerApc;
96 KDPC TimerDpc;
97 LIST_ENTRY ActiveTimerListEntry;
98 KSPIN_LOCK Lock;
99 LONG Period;
100 BOOLEAN ApcAssociated;
101 BOOLEAN WakeTimer;
102 LIST_ENTRY WakeTimerListEntry;
103 } ETIMER, *PETIMER;
104
105 typedef struct
106 {
107 PCALLBACK_OBJECT *CallbackObject;
108 PWSTR Name;
109 } SYSTEM_CALLBACKS;
110
111 typedef struct _HARDERROR_USER_PARAMETERS
112 {
113 ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS];
114 UNICODE_STRING Strings[MAXIMUM_HARDERROR_PARAMETERS];
115 WCHAR Buffer[ANYSIZE_ARRAY];
116 } HARDERROR_USER_PARAMETERS, *PHARDERROR_USER_PARAMETERS;
117
118 #define MAX_FAST_REFS 7
119
120 #define ExAcquireRundownProtection _ExAcquireRundownProtection
121 #define ExReleaseRundownProtection _ExReleaseRundownProtection
122 #define ExInitializeRundownProtection _ExInitializeRundownProtection
123 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
124 #define ExRundownCompleted _ExRundownCompleted
125 #define ExGetPreviousMode KeGetPreviousMode
126
127
128 //
129 // Various bits tagged on the handle or handle table
130 //
131 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT 1
132 #define FREE_HANDLE_MASK -1
133
134 //
135 // Number of entries in each table level
136 //
137 #define LOW_LEVEL_ENTRIES (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
138 #define MID_LEVEL_ENTRIES (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
139 #define HIGH_LEVEL_ENTRIES (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
140
141 //
142 // Maximum index in each table level before we need another table
143 //
144 #define MAX_LOW_INDEX LOW_LEVEL_ENTRIES
145 #define MAX_MID_INDEX (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
146 #define MAX_HIGH_INDEX (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
147
148 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
149 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
150 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
151
152 NTSTATUS
153 NTAPI
154 ExGetPoolTagInfo(
155 IN PSYSTEM_POOLTAG_INFORMATION SystemInformation,
156 IN ULONG SystemInformationLength,
157 IN OUT PULONG ReturnLength OPTIONAL
158 );
159
160 /* INITIALIZATION FUNCTIONS *************************************************/
161
162 BOOLEAN
163 NTAPI
164 ExpWin32kInit(VOID);
165
166 VOID
167 NTAPI
168 ExInit2(VOID);
169
170 VOID
171 NTAPI
172 Phase1Initialization(
173 IN PVOID Context
174 );
175
176 VOID
177 NTAPI
178 ExpInitializePushLocks(VOID);
179
180 BOOLEAN
181 NTAPI
182 ExRefreshTimeZoneInformation(
183 IN PLARGE_INTEGER SystemBootTime
184 );
185
186 VOID
187 NTAPI
188 ExpInitializeWorkerThreads(VOID);
189
190 VOID
191 NTAPI
192 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap);
193
194 VOID
195 NTAPI
196 ExpInitLookasideLists(VOID);
197
198 VOID
199 NTAPI
200 ExInitializeSystemLookasideList(
201 IN PGENERAL_LOOKASIDE List,
202 IN POOL_TYPE Type,
203 IN ULONG Size,
204 IN ULONG Tag,
205 IN USHORT MaximumDepth,
206 IN PLIST_ENTRY ListHead
207 );
208
209 BOOLEAN
210 NTAPI
211 ExpInitializeCallbacks(VOID);
212
213 VOID
214 NTAPI
215 ExpInitUuids(VOID);
216
217 VOID
218 NTAPI
219 ExpInitializeExecutive(
220 IN ULONG Cpu,
221 IN PLOADER_PARAMETER_BLOCK LoaderBlock
222 );
223
224 BOOLEAN
225 NTAPI
226 ExpInitializeEventImplementation(VOID);
227
228 BOOLEAN
229 NTAPI
230 ExpInitializeKeyedEventImplementation(VOID);
231
232 BOOLEAN
233 NTAPI
234 ExpInitializeEventPairImplementation(VOID);
235
236 BOOLEAN
237 NTAPI
238 ExpInitializeSemaphoreImplementation(VOID);
239
240 BOOLEAN
241 NTAPI
242 ExpInitializeMutantImplementation(VOID);
243
244 BOOLEAN
245 NTAPI
246 ExpInitializeTimerImplementation(VOID);
247
248 BOOLEAN
249 NTAPI
250 ExpInitializeProfileImplementation(VOID);
251
252 VOID
253 NTAPI
254 ExpResourceInitialization(VOID);
255
256 VOID
257 NTAPI
258 ExInitPoolLookasidePointers(VOID);
259
260 /* Callback Functions ********************************************************/
261
262 VOID
263 NTAPI
264 ExInitializeCallBack(
265 IN OUT PEX_CALLBACK Callback
266 );
267
268 PEX_CALLBACK_ROUTINE_BLOCK
269 NTAPI
270 ExAllocateCallBack(
271 IN PEX_CALLBACK_FUNCTION Function,
272 IN PVOID Context
273 );
274
275 VOID
276 NTAPI
277 ExFreeCallBack(
278 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
279 );
280
281 BOOLEAN
282 NTAPI
283 ExCompareExchangeCallBack (
284 IN OUT PEX_CALLBACK CallBack,
285 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
286 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
287 );
288
289 PEX_CALLBACK_ROUTINE_BLOCK
290 NTAPI
291 ExReferenceCallBackBlock(
292 IN OUT PEX_CALLBACK CallBack
293 );
294
295 VOID
296 NTAPI
297 ExDereferenceCallBackBlock(
298 IN OUT PEX_CALLBACK CallBack,
299 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
300 );
301
302 PEX_CALLBACK_FUNCTION
303 NTAPI
304 ExGetCallBackBlockRoutine(
305 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
306 );
307
308 PVOID
309 NTAPI
310 ExGetCallBackBlockContext(
311 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
312 );
313
314 VOID
315 NTAPI
316 ExWaitForCallBacks(
317 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
318 );
319
320 /* Rundown Functions ********************************************************/
321
322 VOID
323 FASTCALL
324 ExfInitializeRundownProtection(
325 OUT PEX_RUNDOWN_REF RunRef
326 );
327
328 VOID
329 FASTCALL
330 ExfReInitializeRundownProtection(
331 OUT PEX_RUNDOWN_REF RunRef
332 );
333
334 BOOLEAN
335 FASTCALL
336 ExfAcquireRundownProtection(
337 IN OUT PEX_RUNDOWN_REF RunRef
338 );
339
340 BOOLEAN
341 FASTCALL
342 ExfAcquireRundownProtectionEx(
343 IN OUT PEX_RUNDOWN_REF RunRef,
344 IN ULONG Count
345 );
346
347 VOID
348 FASTCALL
349 ExfReleaseRundownProtection(
350 IN OUT PEX_RUNDOWN_REF RunRef
351 );
352
353 VOID
354 FASTCALL
355 ExfReleaseRundownProtectionEx(
356 IN OUT PEX_RUNDOWN_REF RunRef,
357 IN ULONG Count
358 );
359
360 VOID
361 FASTCALL
362 ExfRundownCompleted(
363 OUT PEX_RUNDOWN_REF RunRef
364 );
365
366 VOID
367 FASTCALL
368 ExfWaitForRundownProtectionRelease(
369 IN OUT PEX_RUNDOWN_REF RunRef
370 );
371
372 /* HANDLE TABLE FUNCTIONS ***************************************************/
373
374 typedef BOOLEAN
375 (NTAPI *PEX_SWEEP_HANDLE_CALLBACK)(
376 PHANDLE_TABLE_ENTRY HandleTableEntry,
377 HANDLE Handle,
378 PVOID Context
379 );
380
381 typedef BOOLEAN
382 (NTAPI *PEX_DUPLICATE_HANDLE_CALLBACK)(
383 IN PEPROCESS Process,
384 IN PHANDLE_TABLE HandleTable,
385 IN PHANDLE_TABLE_ENTRY HandleTableEntry,
386 IN PHANDLE_TABLE_ENTRY NewEntry
387 );
388
389 typedef BOOLEAN
390 (NTAPI *PEX_CHANGE_HANDLE_CALLBACK)(
391 PHANDLE_TABLE_ENTRY HandleTableEntry,
392 ULONG_PTR Context
393 );
394
395 VOID
396 NTAPI
397 ExpInitializeHandleTables(
398 VOID
399 );
400
401 PHANDLE_TABLE
402 NTAPI
403 ExCreateHandleTable(
404 IN PEPROCESS Process OPTIONAL
405 );
406
407 VOID
408 NTAPI
409 ExUnlockHandleTableEntry(
410 IN PHANDLE_TABLE HandleTable,
411 IN PHANDLE_TABLE_ENTRY HandleTableEntry
412 );
413
414 HANDLE
415 NTAPI
416 ExCreateHandle(
417 IN PHANDLE_TABLE HandleTable,
418 IN PHANDLE_TABLE_ENTRY HandleTableEntry
419 );
420
421 VOID
422 NTAPI
423 ExDestroyHandleTable(
424 IN PHANDLE_TABLE HandleTable,
425 IN PVOID DestroyHandleProcedure OPTIONAL
426 );
427
428 BOOLEAN
429 NTAPI
430 ExDestroyHandle(
431 IN PHANDLE_TABLE HandleTable,
432 IN HANDLE Handle,
433 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
434 );
435
436 PHANDLE_TABLE_ENTRY
437 NTAPI
438 ExMapHandleToPointer(
439 IN PHANDLE_TABLE HandleTable,
440 IN HANDLE Handle
441 );
442
443 PHANDLE_TABLE
444 NTAPI
445 ExDupHandleTable(
446 IN PEPROCESS Process,
447 IN PHANDLE_TABLE HandleTable,
448 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
449 IN ULONG_PTR Mask
450 );
451
452 BOOLEAN
453 NTAPI
454 ExChangeHandle(
455 IN PHANDLE_TABLE HandleTable,
456 IN HANDLE Handle,
457 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
458 IN ULONG_PTR Context
459 );
460
461 VOID
462 NTAPI
463 ExSweepHandleTable(
464 IN PHANDLE_TABLE HandleTable,
465 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
466 IN PVOID Context
467 );
468
469 /* PSEH EXCEPTION HANDLING **************************************************/
470
471 LONG
472 NTAPI
473 ExSystemExceptionFilter(VOID);
474
475 /* CALLBACKS *****************************************************************/
476
477 FORCEINLINE
478 VOID
479 ExDoCallBack(IN OUT PEX_CALLBACK Callback,
480 IN PVOID Context,
481 IN PVOID Argument1,
482 IN PVOID Argument2)
483 {
484 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock;
485 PEX_CALLBACK_FUNCTION Function;
486
487 /* Reference the block */
488 CallbackBlock = ExReferenceCallBackBlock(Callback);
489 if (CallbackBlock)
490 {
491 /* Get the function */
492 Function = ExGetCallBackBlockRoutine(CallbackBlock);
493
494 /* Do the callback */
495 Function(Context, Argument1, Argument2);
496
497 /* Now dereference it */
498 ExDereferenceCallBackBlock(Callback, CallbackBlock);
499 }
500 }
501
502 /* FAST REFS ******************************************************************/
503
504 FORCEINLINE
505 PVOID
506 ExGetObjectFastReference(IN EX_FAST_REF FastRef)
507 {
508 /* Return the unbiased pointer */
509 return (PVOID)(FastRef.Value & ~MAX_FAST_REFS);
510 }
511
512 FORCEINLINE
513 ULONG
514 ExGetCountFastReference(IN EX_FAST_REF FastRef)
515 {
516 /* Return the reference count */
517 return (ULONG)FastRef.RefCnt;
518 }
519
520 FORCEINLINE
521 VOID
522 ExInitializeFastReference(OUT PEX_FAST_REF FastRef,
523 IN OPTIONAL PVOID Object)
524 {
525 /* Sanity check */
526 ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
527
528 /* Check if an object is being set */
529 if (!Object)
530 {
531 /* Clear the field */
532 FastRef->Object = NULL;
533 }
534 else
535 {
536 /* Otherwise, we assume the object was referenced and is ready */
537 FastRef->Value = (ULONG_PTR)Object | MAX_FAST_REFS;
538 }
539 }
540
541 FORCEINLINE
542 EX_FAST_REF
543 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef)
544 {
545 EX_FAST_REF OldValue, NewValue;
546
547 /* Start reference loop */
548 for (;;)
549 {
550 /* Get the current reference count */
551 OldValue = *FastRef;
552 if (OldValue.RefCnt)
553 {
554 /* Increase the reference count */
555 NewValue.Value = OldValue.Value - 1;
556 NewValue.Object = ExpChangePushlock(&FastRef->Object,
557 NewValue.Object,
558 OldValue.Object);
559 if (NewValue.Object != OldValue.Object) continue;
560 }
561
562 /* We are done */
563 break;
564 }
565
566 /* Return the old value */
567 return OldValue;
568 }
569
570 FORCEINLINE
571 BOOLEAN
572 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef,
573 IN PVOID Object)
574 {
575 EX_FAST_REF OldValue, NewValue;
576
577 /* Sanity checks */
578 ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
579
580 /* Start update loop */
581 for (;;)
582 {
583 /* Get the current reference count */
584 OldValue = *FastRef;
585
586 /* Check if the current count is too high or if the pointer changed */
587 if (((OldValue.RefCnt + MAX_FAST_REFS) > MAX_FAST_REFS) ||
588 ((OldValue.Value &~ MAX_FAST_REFS) != (ULONG_PTR)Object))
589 {
590 /* Fail */
591 return FALSE;
592 }
593
594 /* Update the reference count */
595 NewValue.Value = OldValue.Value + MAX_FAST_REFS;
596 NewValue.Object = ExpChangePushlock(&FastRef->Object,
597 NewValue.Object,
598 OldValue.Object);
599 if (NewValue.Object != OldValue.Object) continue;
600
601 /* We are done */
602 break;
603 }
604
605 /* Return success */
606 return TRUE;
607 }
608
609 FORCEINLINE
610 BOOLEAN
611 ExReleaseFastReference(IN PEX_FAST_REF FastRef,
612 IN PVOID Object)
613 {
614 EX_FAST_REF OldValue, NewValue;
615
616 /* Sanity checks */
617 ASSERT(Object != NULL);
618 ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
619
620 /* Start reference loop */
621 for (;;)
622 {
623 /* Get the current reference count */
624 OldValue = *FastRef;
625
626 /* Check if we're full if if the pointer changed */
627 if ((OldValue.Value ^ (ULONG_PTR)Object) >= MAX_FAST_REFS) return FALSE;
628
629 /* Decrease the reference count */
630 NewValue.Value = OldValue.Value + 1;
631 NewValue.Object = ExpChangePushlock(&FastRef->Object,
632 NewValue.Object,
633 OldValue.Object);
634 if (NewValue.Object != OldValue.Object) continue;
635
636 /* We are done */
637 break;
638 }
639
640 /* Return success */
641 return TRUE;
642 }
643
644 FORCEINLINE
645 EX_FAST_REF
646 ExSwapFastReference(IN PEX_FAST_REF FastRef,
647 IN PVOID Object)
648 {
649 EX_FAST_REF NewValue, OldValue;
650
651 /* Sanity check */
652 ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
653
654 /* Check if an object is being set */
655 if (!Object)
656 {
657 /* Clear the field */
658 NewValue.Object = NULL;
659 }
660 else
661 {
662 /* Otherwise, we assume the object was referenced and is ready */
663 NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
664 }
665
666 /* Update the object */
667 OldValue.Object = InterlockedExchangePointer(&FastRef->Object, NewValue.Object);
668 return OldValue;
669 }
670
671 FORCEINLINE
672 EX_FAST_REF
673 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef,
674 IN PVOID Object,
675 IN PVOID OldObject)
676 {
677 EX_FAST_REF OldValue, NewValue;
678
679 /* Sanity check and start swap loop */
680 ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
681 for (;;)
682 {
683 /* Get the current value */
684 OldValue = *FastRef;
685
686 /* Make sure there's enough references to swap */
687 if (!((OldValue.Value ^ (ULONG_PTR)OldObject) <= MAX_FAST_REFS)) break;
688
689 /* Check if we have an object to swap */
690 if (Object)
691 {
692 /* Set up the value with maximum fast references */
693 NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
694 }
695 else
696 {
697 /* Write the object address itself (which is empty) */
698 NewValue.Value = (ULONG_PTR)Object;
699 }
700
701 /* Do the actual compare exchange */
702 NewValue.Object = ExpChangePushlock(&FastRef->Object,
703 NewValue.Object,
704 OldValue.Object);
705 if (NewValue.Object != OldValue.Object) continue;
706
707 /* All done */
708 break;
709 }
710
711 /* Return the old value */
712 return OldValue;
713 }
714
715 /* RUNDOWN *******************************************************************/
716
717 /*++
718 * @name ExfAcquireRundownProtection
719 * INTERNAL MACRO
720 *
721 * The ExfAcquireRundownProtection routine acquires rundown protection for
722 * the specified descriptor.
723 *
724 * @param RunRef
725 * Pointer to a rundown reference descriptor.
726 *
727 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
728 *
729 * @remarks This is the internal macro for system use only.In case the rundown
730 * was active, then the slow-path will be called through the exported
731 * function.
732 *
733 *--*/
734 FORCEINLINE
735 BOOLEAN
736 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
737 {
738 ULONG_PTR Value, NewValue;
739
740 /* Get the current value and mask the active bit */
741 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
742
743 /* Add a reference */
744 NewValue = Value + EX_RUNDOWN_COUNT_INC;
745
746 /* Change the value */
747 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
748 if (NewValue != Value)
749 {
750 /* Rundown was active, use long path */
751 return ExfAcquireRundownProtection(RunRef);
752 }
753
754 /* Success */
755 return TRUE;
756 }
757
758 /*++
759 * @name ExReleaseRundownProtection
760 * INTERNAL MACRO
761 *
762 * The ExReleaseRundownProtection routine releases rundown protection for
763 * the specified descriptor.
764 *
765 * @param RunRef
766 * Pointer to a rundown reference descriptor.
767 *
768 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
769 *
770 * @remarks This is the internal macro for system use only.In case the rundown
771 * was active, then the slow-path will be called through the exported
772 * function.
773 *
774 *--*/
775 FORCEINLINE
776 VOID
777 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
778 {
779 ULONG_PTR Value, NewValue;
780
781 /* Get the current value and mask the active bit */
782 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
783
784 /* Remove a reference */
785 NewValue = Value - EX_RUNDOWN_COUNT_INC;
786
787 /* Change the value */
788 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
789
790 /* Check if the rundown was active */
791 if (NewValue != Value)
792 {
793 /* Rundown was active, use long path */
794 ExfReleaseRundownProtection(RunRef);
795 }
796 else
797 {
798 /* Sanity check */
799 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
800 }
801 }
802
803 /*++
804 * @name ExInitializeRundownProtection
805 * INTERNAL MACRO
806 *
807 * The ExInitializeRundownProtection routine initializes a rundown
808 * protection descriptor.
809 *
810 * @param RunRef
811 * Pointer to a rundown reference descriptor.
812 *
813 * @return None.
814 *
815 * @remarks This is the internal macro for system use only.
816 *
817 *--*/
818 FORCEINLINE
819 VOID
820 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
821 {
822 /* Set the count to zero */
823 RunRef->Count = 0;
824 }
825
826 /*++
827 * @name ExWaitForRundownProtectionRelease
828 * INTERNAL MACRO
829 *
830 * The ExWaitForRundownProtectionRelease routine waits until the specified
831 * rundown descriptor has been released.
832 *
833 * @param RunRef
834 * Pointer to a rundown reference descriptor.
835 *
836 * @return None.
837 *
838 * @remarks This is the internal macro for system use only. If a wait is actually
839 * necessary, then the slow path is taken through the exported function.
840 *
841 *--*/
842 FORCEINLINE
843 VOID
844 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
845 {
846 ULONG_PTR Value;
847
848 /* Set the active bit */
849 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
850 if ((Value) && (Value != EX_RUNDOWN_ACTIVE))
851 {
852 /* If the the rundown wasn't already active, then take the long path */
853 ExfWaitForRundownProtectionRelease(RunRef);
854 }
855 }
856
857 /*++
858 * @name ExRundownCompleted
859 * INTERNAL MACRO
860 *
861 * The ExRundownCompleted routine completes the rundown of the specified
862 * descriptor by setting the active bit.
863 *
864 * @param RunRef
865 * Pointer to a rundown reference descriptor.
866 *
867 * @return None.
868 *
869 * @remarks This is the internal macro for system use only.
870 *
871 *--*/
872 FORCEINLINE
873 VOID
874 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
875 {
876 /* Sanity check */
877 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
878
879 /* Mark the counter as active */
880 ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE);
881 }
882
883 /* PUSHLOCKS *****************************************************************/
884
885 /* FIXME: VERIFY THESE! */
886
887 VOID
888 FASTCALL
889 ExBlockPushLock(
890 IN PEX_PUSH_LOCK PushLock,
891 IN PVOID WaitBlock
892 );
893
894 VOID
895 FASTCALL
896 ExfUnblockPushLock(
897 IN PEX_PUSH_LOCK PushLock,
898 IN PVOID CurrentWaitBlock
899 );
900
901 VOID
902 FASTCALL
903 ExWaitForUnblockPushLock(
904 IN PEX_PUSH_LOCK PushLock,
905 IN PVOID WaitBlock
906 );
907
908 /*++
909 * @name _ExInitializePushLock
910 * INTERNAL MACRO
911 *
912 * The _ExInitializePushLock macro initializes a PushLock.
913 *
914 * @params PushLock
915 * Pointer to the pushlock which is to be initialized.
916 *
917 * @return None.
918 *
919 * @remarks None.
920 *
921 *--*/
922 FORCEINLINE
923 VOID
924 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock)
925 {
926 /* Set the value to 0 */
927 PushLock->Ptr = 0;
928 }
929 #define ExInitializePushLock _ExInitializePushLock
930
931 /*++
932 * @name ExAcquirePushLockExclusive
933 * INTERNAL MACRO
934 *
935 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
936 *
937 * @params PushLock
938 * Pointer to the pushlock which is to be acquired.
939 *
940 * @return None.
941 *
942 * @remarks The function attempts the quickest route to acquire the lock, which is
943 * to simply set the lock bit.
944 * However, if the pushlock is already shared, the slower path is taken.
945 *
946 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
947 * This macro should usually be paired up with KeAcquireCriticalRegion.
948 *
949 *--*/
950 FORCEINLINE
951 VOID
952 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
953 {
954 /* Try acquiring the lock */
955 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
956 {
957 /* Someone changed it, use the slow path */
958 ExfAcquirePushLockExclusive(PushLock);
959 }
960
961 /* Sanity check */
962 ASSERT(PushLock->Locked);
963 }
964
965 /*++
966 * @name ExTryToAcquirePushLockExclusive
967 * INTERNAL MACRO
968 *
969 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
970 *
971 * @params PushLock
972 * Pointer to the pushlock which is to be acquired.
973 *
974 * @return None.
975 *
976 * @remarks The function attempts the quickest route to acquire the lock, which is
977 * to simply set the lock bit.
978 * However, if the pushlock is already shared, the slower path is taken.
979 *
980 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
981 * This macro should usually be paired up with KeAcquireCriticalRegion.
982 *
983 *--*/
984 FORCEINLINE
985 BOOLEAN
986 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
987 {
988 /* Try acquiring the lock */
989 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
990 {
991 /* Can't acquire */
992 return FALSE;
993 }
994
995 /* Got acquired */
996 ASSERT (PushLock->Locked);
997 return TRUE;
998 }
999
1000 /*++
1001 * @name ExAcquirePushLockShared
1002 * INTERNAL MACRO
1003 *
1004 * The ExAcquirePushLockShared macro acquires a shared PushLock.
1005 *
1006 * @params PushLock
1007 * Pointer to the pushlock which is to be acquired.
1008 *
1009 * @return None.
1010 *
1011 * @remarks The function attempts the quickest route to acquire the lock, which is
1012 * to simply set the lock bit and set the share count to one.
1013 * However, if the pushlock is already shared, the slower path is taken.
1014 *
1015 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1016 * This macro should usually be paired up with KeAcquireCriticalRegion.
1017 *
1018 *--*/
1019 FORCEINLINE
1020 VOID
1021 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
1022 {
1023 EX_PUSH_LOCK NewValue;
1024
1025 /* Try acquiring the lock */
1026 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1027 if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
1028 {
1029 /* Someone changed it, use the slow path */
1030 ExfAcquirePushLockShared(PushLock);
1031 }
1032
1033 /* Sanity checks */
1034 ASSERT(PushLock->Locked);
1035 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
1036 }
1037
1038 /*++
1039 * @name ExConvertPushLockSharedToExclusive
1040 * INTERNAL MACRO
1041 *
1042 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
1043 * pushlock to a shared pushlock.
1044 *
1045 * @params PushLock
1046 * Pointer to the pushlock which is to be converted.
1047 *
1048 * @return FALSE if conversion failed, TRUE otherwise.
1049 *
1050 * @remarks The function attempts the quickest route to convert the lock, which is
1051 * to simply set the lock bit and remove any other bits.
1052 *
1053 *--*/
1054 FORCEINLINE
1055 BOOLEAN
1056 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
1057 {
1058 EX_PUSH_LOCK OldValue;
1059
1060 /* Set the expected old value */
1061 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1062
1063 /* Try converting the lock */
1064 if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
1065 OldValue.Ptr)
1066 {
1067 /* Conversion failed */
1068 return FALSE;
1069 }
1070
1071 /* Sanity check */
1072 ASSERT(PushLock->Locked);
1073 return TRUE;
1074 }
1075
1076 /*++
1077 * @name ExWaitOnPushLock
1078 * INTERNAL MACRO
1079 *
1080 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1081 *
1082 * @params PushLock
1083 * Pointer to a pushlock.
1084 *
1085 * @return None.
1086 *
1087 * @remarks The function attempts to get any exclusive waiters out of their slow
1088 * path by forcing an instant acquire/release operation.
1089 *
1090 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1091 *
1092 *--*/
1093 FORCEINLINE
1094 VOID
1095 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
1096 {
1097 /* Check if we're locked */
1098 if (PushLock->Locked)
1099 {
1100 /* Acquire the lock */
1101 ExfAcquirePushLockExclusive(PushLock);
1102 ASSERT(PushLock->Locked);
1103
1104 /* Release it */
1105 ExfReleasePushLockExclusive(PushLock);
1106 }
1107 }
1108
1109 /*++
1110 * @name ExReleasePushLockShared
1111 * INTERNAL MACRO
1112 *
1113 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1114 *
1115 * @params PushLock
1116 * Pointer to a previously acquired pushlock.
1117 *
1118 * @return None.
1119 *
1120 * @remarks The function attempts the quickest route to release the lock, which is
1121 * to simply decrease the share count and remove the lock bit.
1122 * However, if the pushlock is being waited on then the long path is taken.
1123 *
1124 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1125 * This macro should usually be paired up with KeLeaveCriticalRegion.
1126 *
1127 *--*/
1128 FORCEINLINE
1129 VOID
1130 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
1131 {
1132 EX_PUSH_LOCK OldValue;
1133
1134 /* Sanity checks */
1135 ASSERT(PushLock->Locked);
1136 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
1137
1138 /* Try to clear the pushlock */
1139 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1140 if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
1141 {
1142 /* There are still other people waiting on it */
1143 ExfReleasePushLockShared(PushLock);
1144 }
1145 }
1146
1147 /*++
1148 * @name ExReleasePushLockExclusive
1149 * INTERNAL MACRO
1150 *
1151 * The ExReleasePushLockExclusive macro releases a previously
1152 * exclusively acquired PushLock.
1153 *
1154 * @params PushLock
1155 * Pointer to a previously acquired pushlock.
1156 *
1157 * @return None.
1158 *
1159 * @remarks The function attempts the quickest route to release the lock, which is
1160 * to simply clear the locked bit.
1161 * However, if the pushlock is being waited on, the slow path is taken
1162 * in an attempt to wake up the lock.
1163 *
1164 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1165 * This macro should usually be paired up with KeLeaveCriticalRegion.
1166 *
1167 *--*/
1168 FORCEINLINE
1169 VOID
1170 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
1171 {
1172 EX_PUSH_LOCK OldValue;
1173
1174 /* Sanity checks */
1175 ASSERT(PushLock->Locked);
1176 ASSERT(PushLock->Waiting || PushLock->Shared == 0);
1177
1178 /* Unlock the pushlock */
1179 OldValue.Value = InterlockedExchangeAddSizeT((PSIZE_T)PushLock,
1180 -(SSIZE_T)EX_PUSH_LOCK_LOCK);
1181
1182 /* Sanity checks */
1183 ASSERT(OldValue.Locked);
1184 ASSERT(OldValue.Waiting || OldValue.Shared == 0);
1185
1186 /* Check if anyone is waiting on it and it's not already waking*/
1187 if ((OldValue.Waiting) && !(OldValue.Waking))
1188 {
1189 /* Wake it up */
1190 ExfTryToWakePushLock(PushLock);
1191 }
1192 }
1193
1194 /*++
1195 * @name ExReleasePushLock
1196 * INTERNAL MACRO
1197 *
1198 * The ExReleasePushLock macro releases a previously acquired PushLock.
1199 *
1200 * @params PushLock
1201 * Pointer to a previously acquired pushlock.
1202 *
1203 * @return None.
1204 *
1205 * @remarks The function attempts the quickest route to release the lock, which is
1206 * to simply clear all the fields and decrease the share count if required.
1207 * However, if the pushlock is being waited on then the long path is taken.
1208 *
1209 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1210 * This macro should usually be paired up with KeLeaveCriticalRegion.
1211 *
1212 *--*/
1213 FORCEINLINE
1214 VOID
1215 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
1216 {
1217 EX_PUSH_LOCK OldValue = *PushLock;
1218 EX_PUSH_LOCK NewValue;
1219
1220 /* Sanity checks */
1221 ASSERT(OldValue.Locked);
1222
1223 /* Check if the pushlock is shared */
1224 if (OldValue.Shared > 1)
1225 {
1226 /* Decrease the share count */
1227 NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
1228 }
1229 else
1230 {
1231 /* Clear the pushlock entirely */
1232 NewValue.Value = 0;
1233 }
1234
1235 /* Check if nobody is waiting on us and try clearing the lock here */
1236 if ((OldValue.Waiting) ||
1237 (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
1238 OldValue.Ptr))
1239 {
1240 /* We have waiters, use the long path */
1241 ExfReleasePushLock(PushLock);
1242 }
1243 }
1244
1245 /* FAST MUTEX INLINES *********************************************************/
1246
1247 FORCEINLINE
1248 VOID
1249 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex)
1250 {
1251 PKTHREAD Thread = KeGetCurrentThread();
1252
1253 /* Sanity check */
1254 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1255 (Thread->CombinedApcDisable != 0) ||
1256 (Thread->Teb == NULL) ||
1257 (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1258 ASSERT(FastMutex->Owner != Thread);
1259
1260 /* Decrease the count */
1261 if (InterlockedDecrement(&FastMutex->Count))
1262 {
1263 /* Someone is still holding it, use slow path */
1264 KiAcquireFastMutex(FastMutex);
1265 }
1266
1267 /* Set the owner */
1268 FastMutex->Owner = Thread;
1269 }
1270
1271 FORCEINLINE
1272 VOID
1273 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1274 {
1275 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1276 (KeGetCurrentThread()->CombinedApcDisable != 0) ||
1277 (KeGetCurrentThread()->Teb == NULL) ||
1278 (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1279 ASSERT(FastMutex->Owner == KeGetCurrentThread());
1280
1281 /* Erase the owner */
1282 FastMutex->Owner = NULL;
1283
1284 /* Increase the count */
1285 if (InterlockedIncrement(&FastMutex->Count) <= 0)
1286 {
1287 /* Someone was waiting for it, signal the waiter */
1288 KeSetEventBoostPriority(&FastMutex->Event, NULL);
1289 }
1290 }
1291
1292 FORCEINLINE
1293 VOID
1294 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
1295 {
1296 KIRQL OldIrql;
1297 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1298
1299 /* Raise IRQL to APC */
1300 KeRaiseIrql(APC_LEVEL, &OldIrql);
1301
1302 /* Decrease the count */
1303 if (InterlockedDecrement(&FastMutex->Count))
1304 {
1305 /* Someone is still holding it, use slow path */
1306 KiAcquireFastMutex(FastMutex);
1307 }
1308
1309 /* Set the owner and IRQL */
1310 FastMutex->Owner = KeGetCurrentThread();
1311 FastMutex->OldIrql = OldIrql;
1312 }
1313
1314 FORCEINLINE
1315 VOID
1316 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex)
1317 {
1318 KIRQL OldIrql;
1319 ASSERT(KeGetCurrentIrql() == APC_LEVEL);
1320
1321 /* Erase the owner */
1322 FastMutex->Owner = NULL;
1323 OldIrql = (KIRQL)FastMutex->OldIrql;
1324
1325 /* Increase the count */
1326 if (InterlockedIncrement(&FastMutex->Count) <= 0)
1327 {
1328 /* Someone was waiting for it, signal the waiter */
1329 KeSetEventBoostPriority(&FastMutex->Event, NULL);
1330 }
1331
1332 /* Lower IRQL back */
1333 KeLowerIrql(OldIrql);
1334 }
1335
1336 FORCEINLINE
1337 BOOLEAN
1338 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex)
1339 {
1340 KIRQL OldIrql;
1341 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1342
1343 /* Raise to APC_LEVEL */
1344 KeRaiseIrql(APC_LEVEL, &OldIrql);
1345
1346 /* Check if we can quickly acquire it */
1347 if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
1348 {
1349 /* We have, set us as owners */
1350 FastMutex->Owner = KeGetCurrentThread();
1351 FastMutex->OldIrql = OldIrql;
1352 return TRUE;
1353 }
1354 else
1355 {
1356 /* Acquire attempt failed */
1357 KeLowerIrql(OldIrql);
1358 YieldProcessor();
1359 return FALSE;
1360 }
1361 }
1362
1363 FORCEINLINE
1364 VOID
1365 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1366 {
1367 /* Enter the Critical Region */
1368 KeEnterCriticalRegion();
1369
1370 /* Acquire the mutex unsafely */
1371 _ExAcquireFastMutexUnsafe(FastMutex);
1372 }
1373
1374 FORCEINLINE
1375 VOID
1376 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex)
1377 {
1378 /* Release the mutex unsafely */
1379 _ExReleaseFastMutexUnsafe(FastMutex);
1380
1381 /* Leave the critical region */
1382 KeLeaveCriticalRegion();
1383 }
1384
1385 /* OTHER FUNCTIONS **********************************************************/
1386
1387 BOOLEAN
1388 NTAPI
1389 ExTryToAcquireResourceExclusiveLite(
1390 IN PERESOURCE Resource
1391 );
1392
1393 NTSTATUS
1394 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation);
1395
1396 BOOLEAN
1397 NTAPI
1398 ExAcquireTimeRefreshLock(BOOLEAN Wait);
1399
1400 VOID
1401 NTAPI
1402 ExReleaseTimeRefreshLock(VOID);
1403
1404 VOID
1405 NTAPI
1406 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
1407 IN ULONG MaxSepInSeconds);
1408
1409 NTSTATUS
1410 NTAPI
1411 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
1412
1413 VOID
1414 NTAPI
1415 ExTimerRundown(VOID);
1416
1417 VOID
1418 NTAPI
1419 HeadlessInit(
1420 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1421 );
1422
1423 VOID
1424 NTAPI
1425 XIPInit(
1426 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1427 );
1428
1429 #define InterlockedDecrementUL(Addend) \
1430 (ULONG)InterlockedDecrement((PLONG)(Addend))
1431
1432 #define InterlockedIncrementUL(Addend) \
1433 (ULONG)InterlockedIncrement((PLONG)(Addend))
1434
1435 #define InterlockedExchangeUL(Target, Value) \
1436 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1437
1438 #define InterlockedExchangeAddUL(Addend, Value) \
1439 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1440
1441 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1442 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1443
1444 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1445 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))