SheafSystem  0.0.0.0
read_write_monitor.cc
1 
2 //
3 // Copyright (c) 2014 Limit Point Systems, Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 
18 // Implementation for class READ_WRITE_MONITOR
19 
20 #include "SheafSystem/read_write_monitor.h"
21 #include "SheafSystem/assert_contract.h"
22 #include "SheafSystem/std_cstdlib.h"
23 #include "SheafSystem/std_iostream.h"
24 
25 // ===========================================================
26 // READ_WRITE_MONITOR FACET
27 // ===========================================================
28 
29 // PUBLIC MEMBER FUNCTIONS
30 
31 
34 {
35 
36  // Preconditions:
37 
38  // None.
39 
40  // Body:
41 
42  // Prevent recursive calls to invariant and disable access guards.
43 
46 
47 #ifdef _PTHREADS
48 
49  int rtncode = pthread_mutex_init(&read_write_monitor_mutex,0);
50  if (rtncode == 0)
51  {
52  rtncode = pthread_cond_init(&lock_free,0);
53  }
54 
55  // postconditions:
56 
57  ensure(rtncode == 0);
58 
59  rtncode = pthread_mutex_lock(&read_write_monitor_mutex);
60  if (rtncode == 0)
61  {
62 #endif
63 
64  // Set initial state to no access
65 
66  _ro_ct = 0;
67  _mode_lock_ct = 0;
68  _rw_ct = 0;
69 
70  initialize_thread_state();
71  access_mode() = 0;
72 
73  // Postconditions:
74 
75  ensure(invariant());
76 
77 #ifdef _PTHREADS
78 
79  rtncode = pthread_mutex_unlock(&read_write_monitor_mutex);
80  }
81 
82  ensure(rtncode == 0);
83 
84 #endif
85 
86  // Re-enable access guards and invariant.
87 
90 }
91 
92 
95 {
96 
97  // Preconditions:
98 
99  // Body:
100 
101  // Nothing to do.
102 
103  // Postconditions:
104 
105  // None.
106 
107 }
108 
109 // PROTECTED MEMBER FUNCTIONS
110 
111 // PRIVATE MEMBER FUNCTIONS
112 
113 // ===========================================================
114 // GLOBAL ACCESS CONTROL FACET
115 // ===========================================================
116 
117 // PUBLIC MEMBER FUNCTIONS
118 
119 bool
122 {
123  return private_access_control_disabled();
124 }
125 
126 // void
127 // sheaf::read_write_monitor::
128 // disable_access_control()
129 // {
130 // // cout << endl << "Entering read_write_monitor::disable_access_control." << endl;
131 
132 // // Preconditions:
133 
134 // // Body:
135 
136 // private_access_control_disabled() = true;
137 
138 // // Postconditions:
139 
140 // ensure(access_control_disabled());
141 
142 // // Exit:
143 
144 // // cout << "Leaving read_write_monitor::disable_access_control." << endl;
145 // return;
146 // }
147 
148 void
151 {
152  // cout << endl << "Entering read_write_monitor::enable_access_control." << endl;
153 
154  // Preconditions:
155 
156  // Body:
157 
158  private_access_control_disabled() = false;
159 
160  // Postconditions:
161 
162  ensure(!access_control_disabled());
163 
164  // Exit:
165 
166  // cout << "Leaving read_write_monitor::enable_access_control." << endl;
167  return;
168 }
169 
170 // PROTECTED MEMBER FUNCTIONS
171 
172 // PRIVATE MEMBER FUNCTIONS
173 
174 bool&
175 sheaf::read_write_monitor::
176 private_access_control_disabled()
177 {
178  // cout << endl << "Entering read_write_monitor::private_access_control_disabled." << endl;
179 
180  // Preconditions:
181 
182 
183  // Body:
184 
185  static bool result = true;
186 
187  // Postconditions:
188 
189 
190  // Exit:
191 
192  // cout << "Leaving read_write_monitor::private_access_control_disabled." << endl;
193  return result;
194 }
195 
196 
197 // ===========================================================
198 // PER-THREAD ACCESS CONTROL FACET
199 // ===========================================================
200 
201 // PUBLIC MEMBER FUNCTIONS
202 
203 bool
206 {
207  bool result;
208 
209  // Preconditions:
210 
211  // Body:
212 
214 
215  // Postconditions:
216 
217  ensure(result == (is_read_only_accessible() || is_read_write_accessible()));
218 
219  // Exit:
220 
221  return result;
222 }
223 
224 bool
227 {
228  bool result;
229 
230  // Preconditions:
231 
232  // Body:
233 
235 
236  // Postconditions:
237 
238  ensure(result == (access_control_disabled() || !is_read_accessible()));
239 
240  // Exit:
241 
242  return result;
243 }
244 
245 bool
248 {
249  bool result;
250 
251  // Body:
252 
253 
254  // Is accessible if access guards disabled.
255 
256  result = access_control_disabled() || access_guards_disabled() || uncontrolled_is_read_write_accessible();
257 
258  // Postcondition:
259 
260  ensure((access_control_disabled() || access_guards_disabled()) ? result : true);
261 
262  // Exit:
263 
264  return result;
265 }
266 
267 bool
270 {
271 
272  // Body:
273 
274  bool result = access_control_disabled() ? true: !is_read_write_accessible();
275 
276 
277  // Postcondition:
278 
279  ensure(result == (access_control_disabled() ? true: !is_read_write_accessible()));
280 
281  // Exit:
282 
283  return result;
284 }
285 
286 bool
289 {
290  bool result;
291 
292  // Preconditions:
293 
294  // Body:
295 
296 
297  // Is not accessible if access guards disabled.
298 
299  result = !access_control_disabled() && !access_guards_disabled() && uncontrolled_is_read_only_accessible();
300 
301  // Postcondition:
302 
303  ensure((access_control_disabled() || access_guards_disabled()) ? !result : true);
304 
305  // Exit:
306 
307  return result;
308 }
309 
310 
311 bool
314 {
315  bool result;
316 
317  // Preconditions:
318 
319  // Body:
320 
321  // This function is not really necessary,
322  // it is provided only for symmetry with the
323  // other is_not functions, makes it easier
324  // to read and unserstand code in some places.
325 
326  result = !is_read_only_accessible();
327 
328  // Postcondition:
329 
330  ensure(result == !is_read_only_accessible());
331 
332  // Exit:
333 
334  // Note that there's no race condition in returning the result
335  // since each thread has its own copy of result on its own stack.
336 
337  return result;
338 }
339 
340 int
343 {
344  int result;
345 
346  // Preconditions:
347 
348  // Body:
349 
350 #ifdef _PTHREADS
351 
352  pthread_mutex_lock(&read_write_monitor_mutex);
353 #endif
354 
355  result = abs(access_mode());
356 
357 #ifdef _PTHREADS
358 
359  pthread_mutex_unlock(&read_write_monitor_mutex);
360 #endif
361 
362  // Exit:
363 
364  return result;
365 }
366 
367 void
370 {
371 
372  // Preconditions:
373 
374  // Body:
375 
376  if(uncontrolled_is_read_write_accessible())
377  {
378  // Read_write access implies read access, so if the thread
379  // already has read_write access, request it again.
380  // This will just increase the request nesting depth.
381 
382  request_read_write_access();
383  }
384  else
385  {
386  // The thread either has no access or read_only access
387  // Either way, request read_only access. If the thread already
388  // has access, this will just increase the request nesting depth
389 
390  request_read_only_access();
391  }
392 
393 
394  // Postconditions:
395 
396  ensure(is_read_accessible());
397 
398  // Exit
399 
400  return;
401 }
402 
403 
405 void
407 get_read_write_access(bool xrelease_read_only_access)
408 {
409 
410  // Preconditions:
411 
412  require(xrelease_read_only_access || !is_read_only_accessible());
413 
414  // Body:
415 
416  int old_access_request_depth = access_request_depth();
417 
418  if(xrelease_read_only_access && uncontrolled_is_read_only_accessible())
419  {
420  // The client requested that read only access be released and
421  // this is read only accessible. Release the read-only access
422  // and request the same level of read-write access.
423 
424  // Set the switch level so we can restore read-only
425  // access when this write access is released.
426 
427  switch_depth() = old_access_request_depth;
428 
429  // Release all the read-only access.
430 
431  while(uncontrolled_is_read_only_accessible())
432  {
433  release_read_only_access();
434  }
435 
436  // Request the same level of read-write-access.
437 
438  while(access_request_depth() < old_access_request_depth)
439  {
440  request_read_write_access();
441  }
442 
443  assertion(uncontrolled_is_read_write_accessible() &&
444  (access_request_depth() == old_access_request_depth));
445  }
446 
447  // Request read/write access.
448 
449  request_read_write_access();
450 
451  // Postconditions:
452 
453  ensure(is_read_write_accessible());
454  ensure(access_request_depth() == old_access_request_depth + 1);
455 
456  // Exit
457 
458  return;
459 }
460 
461 void
463 release_access(bool xall) const
464 {
465 
466  // Preconditions:
467 
468  require(is_read_accessible());
469 
470  // Body.
471 
472  if(uncontrolled_is_read_write_accessible())
473  {
474  // Release at least one level of read-write access,
475  // and if xall, release all levels.
476 
477  do
478  {
479  release_read_write_access();
480  }
481  while(xall && uncontrolled_is_read_write_accessible());
482 
483  if(uncontrolled_is_read_write_accessible() && (access_request_depth() == switch_depth()))
484  {
485  // We didn't release all levels and we're at the switch level.
486  // Convert remaining read-write access levels
487  // back to read-only levels.
488 
489  while(uncontrolled_is_read_write_accessible())
490  {
491  release_read_write_access();
492  }
493 
494  while(access_request_depth() < switch_depth())
495  {
496  request_read_only_access();
497  }
498 
499  assertion(uncontrolled_is_read_only_accessible() && (access_request_depth() == switch_depth()));
500 
501  switch_depth() = 0;
502  }
503  }
504  else if(uncontrolled_is_read_only_accessible())
505  {
506  // Release at least one level of read-only access,
507  // and if xall, release all levels.
508 
509  do
510  {
511  release_read_only_access();
512  }
513  while(xall && uncontrolled_is_read_only_accessible());
514  }
515 
516  // Postconditions:
517 
518  ensure(xall ? is_not_read_accessible() : true);
519 
520  // Exit:
521 
522  return;
523 }
524 
525 
526 
527 // PROTECTED MEMBER FUNCTIONS
528 
529 
530 
531 
532 // ===========================================================
533 // PRIVATE MEMEBR FUNCTIONS FACET
534 // ===========================================================
535 
536 bool
539 {
540  // Exit:
541 
542  return _access_guards_disabled;
543 }
544 
545 void
548 {
549  _access_guards_disabled = true;
550 
551  return;
552 }
553 
554 void
557 {
558  _access_guards_disabled = false;
559 
560  return;
561 }
562 
563 // PRIVATE MEMBER FUNCTIONS
564 
565 
566 // bool
567 // sheaf::read_write_monitor::
568 // uncontrolled_is_read_write_accessible() const
569 // {
570 // bool result;
571 
572 // // Body:
573 
574 // #ifdef _PTHREADS
575 
576 // pthread_mutex_lock(&read_write_monitor_mutex);
577 // #endif
578 
579 // // Is accessible is access guards disabled.
580 
581 // result = access_guards_disabled() || (access_mode() > 0);
582 
583 // #ifdef _PTHREADS
584 
585 // pthread_mutex_unlock(&read_write_monitor_mutex);
586 // #endif
587 
588 // // Postcondition:
589 
590 // ensure(access_guards_disabled() ? result : true);
591 
592 // // Exit:
593 
594 // // Note that there's no race condition in returning the result
595 // // since each thread has its own copy of result on its own stack.
596 
597 // return result;
598 // }
599 
600 bool
601 sheaf::read_write_monitor::
602 uncontrolled_is_read_write_accessible() const
603 {
604  bool result;
605 
606  // Body:
607 
608 #ifdef _PTHREADS
609 
610  pthread_mutex_lock(&read_write_monitor_mutex);
611 #endif
612 
613  result = (access_mode() > 0);
614 
615 #ifdef _PTHREADS
616 
617  pthread_mutex_unlock(&read_write_monitor_mutex);
618 #endif
619 
620  // Postcondition:
621 
622  // Exit:
623 
624  // Note that there's no race condition in returning the result
625  // since each thread has its own copy of result on its own stack.
626 
627  return result;
628 }
629 
630 
631 // bool
632 // sheaf::read_write_monitor::
633 // uncontrolled_is_read_only_accessible() const
634 // {
635 // bool result;
636 
637 // // Preconditions:
638 
639 // // Body:
640 
641 // #ifdef _PTHREADS
642 
643 // pthread_mutex_lock(&read_write_monitor_mutex);
644 // #endif
645 
646 // result = !access_guards_disabled() && (access_mode() < 0);
647 
648 // #ifdef _PTHREADS
649 
650 // pthread_mutex_unlock(&read_write_monitor_mutex);
651 // #endif
652 
653 // // Postcondition:
654 
655 // ensure(access_guards_disabled() ? !result : true);
656 
657 // // Exit:
658 
659 // // Note that there's no race condition in returning the result
660 // // since each thread has its own copy of result on its own stack.
661 
662 // return result;
663 // }
664 
665 
666 bool
667 sheaf::read_write_monitor::
668 uncontrolled_is_read_only_accessible() const
669 {
670  bool result;
671 
672  // Preconditions:
673 
674  // Body:
675 
676 #ifdef _PTHREADS
677 
678  pthread_mutex_lock(&read_write_monitor_mutex);
679 #endif
680 
681  result = (access_mode() < 0);
682 
683 #ifdef _PTHREADS
684 
685  pthread_mutex_unlock(&read_write_monitor_mutex);
686 #endif
687 
688  // Postcondition:
689 
690  // Exit:
691 
692  // Note that there's no race condition in returning the result
693  // since each thread has its own copy of result on its own stack.
694 
695  return result;
696 }
697 
698 
699 void
700 sheaf::read_write_monitor::
701 initialize_thread_state()
702 {
703 #ifdef _PTHREADS
704 
705  // Preconditions:
706 
707  require(!contains_thread_state());
708 
709  // Body:
710 
711  // Create a new state initialized to no access and not modified.
712 
713  thread_state_t new_thread_state = {0, false};
714 
715  // Insert the new state in the map for this thread..
716 
717  unordered_map<pthread_t, thread_state_t>::value_type lval(pthread_self(), new_thread_state);
718  _thread_state.insert(lval);
719 
720  // Postconditions:
721 
722  ensure(contains_thread_state());
723 
724 #else
725 
726  // Preconditions:
727 
728  // Always contains thread state.
729 
730  // Body:
731 
732  // There's only one thread, just initialize data member
733  // to no access, no switch, and not modified.
734 
735  _thread_state._access_mode = 0;
736  _thread_state._switch_depth = 0;
737  _thread_state._is_modified = false;
738 
739  // Postconditions:
740 
741  ensure(contains_thread_state());
742 
743 #endif
744 
745 }
746 
747 bool
748 sheaf::read_write_monitor::
749 contains_thread_state() const
750 {
751  bool result;
752 
753  // Preconditions:
754 
755 
756  // Body:
757 
758 #ifdef _PTHREADS
759 
760  // Thread state exists if it's in the thread map.
761 
762  result = (_thread_state.find(pthread_self()) != _thread_state.end());
763 
764 #else
765 
766  // There's only one thread and state is a data member.
767 
768  result = true;
769 
770 #endif
771 
772  // Postconditions:
773 
774 
775  // Exit:
776 
777  return result;
778 }
779 
780 
781 sheaf::read_write_monitor::thread_state_t&
782 sheaf::read_write_monitor::
783 thread_state() const
784 {
785  // Preconditions:
786 
787  require(contains_thread_state());
788 
789  // Body:
790 
791 #ifdef _PTHREADS
792 
793  return *_thread_state.find(pthread_self());
794 
795 #else
796 
797  return _thread_state;
798 
799 #endif
800 
801 }
802 
803 int&
804 sheaf::read_write_monitor::
805 access_mode() const
806 {
807  // Preconditions:
808 
809  require(contains_thread_state());
810 
811  // Body:
812 
813  // Postconditions:
814 
815 
816  // Exit:
817 
818  return thread_state()._access_mode;
819 }
820 
821 
822 size_t&
823 sheaf::read_write_monitor::
824 switch_depth() const
825 {
826  // Preconditions:
827 
828  require(contains_thread_state());
829 
830  // Body:
831 
832  // Postconditions:
833 
834 
835  // Exit:
836 
837  return thread_state()._switch_depth;
838 }
839 
840 void
841 sheaf::read_write_monitor::
842 request_read_only_access() const
843 {
844 
845 #ifdef _PTHREADS
846  pthread_mutex_lock(&read_write_monitor_mutex);
847 #endif
848 
849  // Preconditions:
850 
851  require( access_mode() <= 0 );
852 
853  // Body:
854 
855 #ifdef _PTHREADS
856 
857  // wait until any writer has released access
858 
859  while( _rw_ct > 0 )
860  {
861  pthread_cond_wait(&lock_free, &read_write_monitor_mutex);
862  }
863 
864 #endif
865 
866  // Grab read-only access.
867 
868  int& state = access_mode();
869  if(state == 0)
870  {
871  // Thread is just becoming a reader;
872  // increment the thread reader count.
873 
874  _ro_ct++;
875 
876  // Access request nesting depth is -1.
877  // ( < 0 for read-only, 1 for first request)
878 
879  state = -1;
880  }
881  else
882  {
883  // Thread already has read-only access,
884  // just increase the access request nesting depth.
885 
886  state--;
887  }
888 
889 
890  // Postconditions:
891 
892  ensure(invariant());
893  ensure(_rw_ct == 0);
894  ensure(_ro_ct > 0);
895 
896 #ifdef _PTHREADS
897 
898  pthread_mutex_unlock(&read_write_monitor_mutex);
899 #endif
900 
901  // Exit:
902 
903  return;
904 }
905 
906 void
907 sheaf::read_write_monitor::
908 request_read_write_access() const
909 {
910 
911 #ifdef _PTHREADS
912  pthread_mutex_lock(&read_write_monitor_mutex);
913 #endif
914 
915  // Preconditions:
916 
917  require(access_mode() >= 0);
918 
919  // Body:
920 
921  int& state = access_mode();
922  if( state > 0 )
923  {
924  // This thread already has read_write access.
925  // Assuming a "proper" client, this must be a nested call;
926  // Just increase the access request nesting depth
927 
928  state++;
929  }
930  else
931  {
932  // This thread does not have read_write access;
933 
934 #ifdef _PTHREADS
935 
936  // wait until the writer and all readers release access.
937 
938  while( _ro_ct > 0 || _rw_ct > 0)
939  {
940  pthread_cond_wait(&lock_free, &read_write_monitor_mutex);
941  }
942 
943 #endif
944 
945  // grab read_write access
946 
947  _rw_ct = 1;
948  state = 1;
949 
950  }
951 
952 
953  // postconditions:
954 
955  ensure(invariant());
956  ensure(_ro_ct == 0);
957  ensure(_rw_ct == 1);
958  ensure(access_mode() > 0);
959 
960 #ifdef _PTHREADS
961 
962  pthread_mutex_unlock(&read_write_monitor_mutex);
963 #endif
964 
965  return;
966 }
967 
968 
969 void
970 sheaf::read_write_monitor::
971 release_read_only_access() const
972 {
973 
974 
975 #ifdef _PTHREADS
976  pthread_mutex_lock(&read_write_monitor_mutex);
977 #endif
978 
979 
980  // Preconditions:
981 
982  require( access_mode() < 0 );
983 
984  // Body:
985 
986  // Get the thread state
987 
988  int& state = access_mode();
989 
990  // Decrease the request nesting depth
991 
992  state++;
993 
994  // Save the number of readers for the postcondition
995 
996  define_old_variable(int old_ro_ct = _ro_ct);
997 
998  // If this thread is no longer a reader,
999  // Decrement the number of readers.
1000 
1001  if(state == 0)
1002  _ro_ct--;
1003 
1004 
1005 #ifdef _PTHREADS
1006 
1007  // If no readers left, unlock for writers
1008 
1009  // Use signal instead of broadcast since only writers
1010  // should be queued up waiting for access and only 1
1011  // writer at a time can get access.
1012 
1013  if (_ro_ct == 0)
1014  pthread_cond_signal(&lock_free);
1015 
1016 #endif
1017 
1018 
1019  // Postconditions:
1020 
1021  ensure(invariant());
1022  ensure((_ro_ct == old_ro_ct) || (_ro_ct == old_ro_ct - 1));
1023 
1024 #ifdef _PTHREADS
1025 
1026  pthread_mutex_unlock(&read_write_monitor_mutex);
1027 #endif
1028 
1029  return;
1030 }
1031 
1033 void
1034 sheaf::read_write_monitor::
1035 release_read_write_access() const
1036 {
1037 
1038 #ifdef _PTHREADS
1039  pthread_mutex_lock(&read_write_monitor_mutex);
1040 #endif
1041 
1042  // Preconditions:
1043 
1044  require( access_mode() > 0 );
1045 
1046  // Body:
1047 
1048  // Get the thread access state
1049 
1050  int& state = access_mode();
1051 
1052  // Decrease the nesting depth of write requests
1053 
1054  state--;
1055 
1056  // Save counter for use in postcondition
1057 
1058  define_old_variable(int old_rw_ct = _rw_ct);
1059 
1060  if(state == 0)
1061  {
1062  // This thread is no longer a writer,
1063  // decrement the number of writers.
1064 
1065  _rw_ct = 0;
1066 
1067 #ifdef _PTHREADS
1068 
1069  // Set the modified flag on all threads, including this thread.
1070 
1071  unordered_map<pthread_t, thread_state_t>::iterator itr = _thread_state.begin();
1072 
1073  while(itr != _thread_state.end())
1074  {
1075  itr->second._is_modified = true;
1076  itr++;
1077  }
1078 
1079  // Unlock for other readers or writers.
1080  // Use broadcast since there might be a lot of readers queued up for
1081  // access. All of them should be permitted access simultaneously.
1082 
1083  pthread_cond_broadcast(&lock_free);
1084 
1085 #else
1086 
1087  // Set the modified flag on this (the only) thread
1088 
1089  _thread_state._is_modified = true;
1090 
1091 #endif
1092 
1093  }
1094 
1095  // Postconditions:
1096 
1097  ensure(invariant());
1098  ensure((_rw_ct == old_rw_ct) || (_rw_ct == old_rw_ct - 1));
1099  ensure(unexecutable("for all client threads: is_modified()"));
1100 
1101 #ifdef _PTHREADS
1102 
1103  pthread_mutex_unlock(&read_write_monitor_mutex);
1104 #endif
1105 
1106  return;
1107 }
1108 
1109 
1110 // ===========================================================
1111 // NOTIFICATION FACET
1112 // ===========================================================
1113 
1114 // PUBLIC MEMBER FUNCTIONS
1115 
1116 bool
1119 {
1120  bool result;
1121 
1122  // Preconditions:
1123 
1124  // Body:
1125 
1126 #ifdef _PTHREADS
1127 
1128  pthread_mutex_lock(&read_write_monitor_mutex);
1129 #endif
1130 
1131  result = thread_state()._is_modified;
1132 
1133 #ifdef _PTHREADS
1134 
1135  pthread_mutex_unlock(&read_write_monitor_mutex);
1136 #endif
1137 
1138  // Exit:
1139 
1140  return result;
1141 }
1142 
1143 
1144 void
1147 {
1148  // Preconditions:
1149 
1150  // Body:
1151 
1152 #ifdef _PTHREADS
1153  pthread_mutex_lock(&read_write_monitor_mutex);
1154 #endif
1155 
1156  thread_state()._is_modified = false;
1157 
1158 #ifdef _PTHREADS
1159 
1160  pthread_mutex_unlock(&read_write_monitor_mutex);
1161 #endif
1162 
1163  // Exit:
1164 
1165  return;
1166 }
1167 
1168 // ===========================================================
1169 // MODEL LOCK CCONTROL FACET
1170 // ===========================================================
1171 
1172 // PUBLIC MEMBER FUNCTIONS
1173 
1174 bool
1177 {
1178  bool result;
1179 
1180  // Preconditions:
1181 
1182  // Body:
1183 
1184 #ifdef _PTHREADS
1185 
1186  pthread_mutex_lock(&read_write_monitor_mutex);
1187 #endif
1188 
1189  result = ( access_guards_disabled() || (_mode_lock_ct > 0));
1190 
1191 #ifdef _PTHREADS
1192 
1193  pthread_mutex_unlock(&read_write_monitor_mutex);
1194 #endif
1195 
1196  // Exit:
1197 
1198  return result;
1199 }
1200 
1201 
1202 int
1205 {
1206  int result;
1207 
1208  // Preconditions:
1209 
1210  // Body:
1211 
1212 #ifdef _PTHREADS
1213 
1214  pthread_mutex_lock(&read_write_monitor_mutex);
1215 #endif
1216 
1217  result = _mode_lock_ct;
1218 
1219 #ifdef _PTHREADS
1220 
1221  pthread_mutex_unlock(&read_write_monitor_mutex);
1222 #endif
1223 
1224  // Exit:
1225 
1226  return result;
1227 }
1228 
1230 void
1233 {
1234 
1235 #ifdef _PTHREADS
1236  pthread_mutex_lock(&read_write_monitor_mutex);
1237 #endif
1238 
1239  // Preconditions:
1240 
1241  // A client can lock the write sub-mode as long as no other
1242  // client is actually using the mode. This can be ensured
1243  // by requiring that no other client has write access, which
1244  // in turn is ensured by this client having either read-only
1245  // or read-write access.
1246 
1247  require( access_mode() != 0 );
1248  // client has either read-only or read-write access
1249 
1250  // Body:
1251 
1252 #ifdef _PTHREADS
1253 
1254  // wait until any writer has released access
1255 
1256  while( _rw_ct > 0 )
1257  {
1258  pthread_cond_wait(&lock_free, &read_write_monitor_mutex);
1259  }
1260 
1261 #endif
1262 
1263  // Save the number of object readers for the postcondition
1264 
1265  define_old_variable(int old_mode_lock_ct = _mode_lock_ct);
1266 
1267  // Increment mode lock ct.
1268 
1269  _mode_lock_ct++;
1270 
1271  // Postconditions:
1272 
1273  ensure(invariant());
1274  ensure(_mode_lock_ct == old_mode_lock_ct + 1);
1275  ensure(_mode_lock_ct > 0);
1276 
1277 #ifdef _PTHREADS
1278 
1279  ensure(_rw_ct == 0);
1280  pthread_mutex_unlock(&read_write_monitor_mutex);
1281 #endif
1282 
1283  // Exit:
1284 
1285  return;
1286 }
1287 
1288 
1289 void
1292 {
1293 
1294 
1295 #ifdef _PTHREADS
1296  pthread_mutex_lock(&read_write_monitor_mutex);
1297 #endif
1298 
1299 
1300  // Preconditions:
1301 
1302  require( _mode_lock_ct > 0 );
1303  // is_mode_locked
1304 
1305  // Body:
1306 
1307  // Save the number of object readers for the postcondition
1308 
1309  define_old_variable(int old_mode_lock_ct = _mode_lock_ct);
1310 
1311  // Decrement the number of object readers.
1312 
1313  _mode_lock_ct--;
1314 
1315 
1316 #ifdef _PTHREADS
1317 
1318  // If no readers left, unlock for writers
1319 
1320  // Use signal instead of broadcast since only writers
1321  // should be queued up waiting for access and only 1
1322  // writer at a time can get access.
1323 
1324  if (_ro_ct == 0)
1325  pthread_cond_signal(&lock_free);
1326 
1327 #endif
1328 
1329 
1330  // Postconditions:
1331 
1332  ensure(invariant());
1333  ensure(_mode_lock_ct == old_mode_lock_ct - 1);
1334 
1335 #ifdef _PTHREADS
1336 
1337  pthread_mutex_unlock(&read_write_monitor_mutex);
1338 #endif
1339 
1340  return;
1341 }
1342 
1343 // PROTECTED MEMBER FUNCTIONS
1344 
1345 // PRIVATE MEMBER FUNCTIONS
1346 
1347 // ===========================================================
1348 // ANY FACET
1349 // ===========================================================
1350 
1351 // PUBLIC MEMBER FUNCTIONS
1352 
1353 bool
1355 is_ancestor_of(const any* xother) const
1356 {
1357  bool result;
1358 
1359  // Preconditions:
1360 
1361  // Body:
1362 
1363  result = dynamic_cast<const read_write_monitor*>(xother) != 0;
1364 
1365  // Postconditions:
1366 
1367  // Exit
1368 
1369  return result;
1370 }
1371 
1372 
1375 clone() const
1376 {
1377  read_write_monitor* result;
1378 
1379  // Preconditions:
1380 
1381  // Body:
1382 
1383  result = new read_write_monitor;
1384 
1385  // Postconditions:
1386 
1387  ensure(result != 0);
1388 
1389  // Exit
1390 
1391  return result;
1392 }
1393 
1394 bool
1396 invariant() const
1397 {
1398  bool result = true;
1399 
1400  // NOTE:
1401  // In the threaded case,
1402  // invariant() should only be called from within a locked read_write_monitor_mutex.
1403  // The reason for this is that one can't compute a true value of the invariant if
1404  // other threads may be manipulating it while the computation is in progress. Yet
1405  // we can't and don't want to lock the invariant itself with read_write_monitor_mutex.
1406  // We can't do so because invariant is properly called from within other
1407  // read_write_monitor procedures (to check their validity). These other procedures
1408  // have already locked read_write_monitor_mutex, and pthreads doesn't allow us to
1409  // lock it again. We don't want to do so because we want the check of the invariant
1410  // to follow immediately after a change of state of the read_write_monitor. If an
1411  // unlock of read_write_monitor_mutex occurs after an operation is done on the state
1412  // of read_write_monitor, but before invariant is actually called, then it isn't
1413  // clear what operations the invariant is checking.
1414  //
1415 
1416  // Body:
1417 
1418  if(invariant_check())
1419  {
1420  // Prevent recursive calls
1421 
1423 
1424  result = result && _ro_ct >= 0;
1425  result = result && _mode_lock_ct >= 0;
1426  result = result && ( (_rw_ct == 0) || (_rw_ct == 1) );
1427  result = result && !( (_rw_ct == 1) && (_ro_ct > 0) );
1428 
1429  // Re-enable invariant check
1430 
1432  }
1433 
1434 
1435  return result;
1436 
1437 }
virtual bool invariant() const
Class invariant.
virtual bool is_ancestor_of(const any *xother) const
True if other conforms to current.
The monitor concurrency control interface. Class READ_WRITE_MONITOR implements the monitor concurrenc...
void enable_access_guards()
Re-enables access guards.
bool is_not_read_only_accessible() const
True if this thread does not have read-only access.
void get_read_access() const
Get read access to the state associated with this.
void clear_is_modified()
Makes is_modified() false.
bool is_read_write_accessible() const
True if this thread has read-write access or if access control is not enabled.
virtual read_write_monitor * clone() const
Make a new instance of the same type as this.
void get_read_write_access(bool xrelease_read_only_access=false)
Get read write access to the state associated with this. If release_read_only_access is requested...
Abstract base class with useful features for all objects.
Definition: any.h:39
bool access_guards_disabled() const
True if access guards disabled.
int access_request_depth() const
Number of times access has been granted without a corresponding release.
void release_access(bool xall=false) const
Release access. If xall is true, release all levels of access. Otherwise, release one level of access...
void disable_access_guards()
Disables access gaurds; intended for use only within constructors of monitored objects, where no other client can possibly have access (yet).
bool is_read_only_accessible() const
True if this thread has read-only access.
read_write_monitor()
Default Constructor.
bool is_not_read_accessible() const
True if this thread has neither read-only or read-write access or if access control is disabled...
void disable_invariant_check() const
Disable invariant check. Intended for preventing recursive calls to invariant and for suppressing inv...
Definition: any.h:97
bool is_not_read_write_accessible() const
True if this thread does not have read-write access or if access control is not enabled.
bool invariant_check() const
True if invariant checking is enabled.
Definition: any.h:79
static bool access_control_disabled()
True if access control mechanism is disabled. Default value is enabled (false) and access is controll...
bool is_modified() const
True if any client has had read-write access to this object since the last call to clear_is_modified(...
virtual ~read_write_monitor()
Destructor.
void enable_invariant_check() const
Enable invariant checking.
Definition: any.h:87
bool is_read_accessible() const
True if this thread has read-only or read-write access.
static void enable_access_control()
Enables access control. Should only be invoked once at beginning of a program, before any other Sheaf...