Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: SS_Message.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | ||
24 | #ifndef __SS_Message_h__ | |
25 | #define __SS_Message_h__ | |
26 | ||
27 | #include "SS_Signal.h" | |
28 | #include "BL_Atomic.h" | |
29 | #include "SS_SnapShot.h" | |
30 | ||
31 | // SS_Message is the container class that holds messages for | |
32 | // a strand that need to be dealth with on the next step. | |
33 | // The class is the crucial element in the run loop of the | |
34 | // strand, and part of it's implementation directly impacts | |
35 | // performance in a big way. The SS_Strand::get_signal is | |
36 | // the only consumer of this class. | |
37 | ||
38 | class SS_Message | |
39 | { | |
40 | public: | |
41 | SS_Message(); | |
42 | ||
43 | // is_pending() returns true if one or more messages have been | |
44 | // send to the strand. This routines is the key test in the | |
45 | // tight runloop of the strand and should not be changed. | |
46 | ||
47 | uint64_t is_pending() | |
48 | { | |
49 | return pending; | |
50 | } | |
51 | ||
52 | // set_reenter_loop() is used to send a message to the strand | |
53 | // that special state such as pstate and hpstate of the strand | |
54 | // changed and w\it needs to get out of the loop to update things | |
55 | // like global variables held in registers. Currently only | |
56 | // SS_Strand::ss_sim_update calls this function. | |
57 | ||
58 | void set_reenter_loop() { flag.reenterloop = 1; } | |
59 | ||
60 | // clr_reenter_loop() is used to notify that the reenter loop | |
61 | // message is handled. | |
62 | ||
63 | void clr_reenter_loop() { flag.reenterloop = 0; } | |
64 | ||
65 | // set_handle_trap() is used to message othe strand that the | |
66 | // next step should launch the trap handler. Only SS_Interrupt | |
67 | // calls this method as it controls which trap is launched. | |
68 | ||
69 | void set_handle_trap( SS_Trap::Type tt ) | |
70 | { | |
71 | assert(tt < SS_Trap::TCC_INSTRUCTION); | |
72 | assert(SS_Trap::Type(flag.trap_type) == SS_Trap::RESERVED); | |
73 | flag.trap_type = tt; | |
74 | } | |
75 | ||
76 | // clr_handle_trap() is used to notify that the trap has been | |
77 | // handled: the strand is now set to step into the trap code. | |
78 | ||
79 | void clr_handle_trap() | |
80 | { | |
81 | flag.trap_type = SS_Trap::RESERVED; | |
82 | } | |
83 | ||
84 | // get_handle_trap() is used to find out if a trap is to be | |
85 | // handled. A return value SS_Trap:RESERVED means no trap. | |
86 | ||
87 | SS_Trap::Type get_handle_trap() | |
88 | { | |
89 | return SS_Trap::Type(flag.trap_type); | |
90 | } | |
91 | ||
92 | // test_signal() returns true while there are SS_Signal type | |
93 | // messages pending. get_signal() is used to consume those | |
94 | // messages. | |
95 | ||
96 | bool test_signal() { return head->next != 0; } | |
97 | ||
98 | // post_signal() is used to send a SS_Signal based message | |
99 | // to the strand. The routine is MP safe; it uses a mutex for enqueue. | |
100 | ||
101 | void post_signal( SS_Signal* node ) | |
102 | { | |
103 | node->next = 0; | |
104 | mutex.lock(); | |
105 | tail = tail->next = node; | |
106 | mutex.unlock(); | |
107 | bl_atomic_add32((int32_t*)&flag.signal,1); | |
108 | } | |
109 | ||
110 | // get_signal() is used by the strand to consume a posted SS_Signal | |
111 | // message. This routine can only be used when test_signal() returns | |
112 | // true. Note each strand has one SS_Message instance so there is | |
113 | // only one user of get_signal(), hence dequeue does not have to | |
114 | // use MP safe constructs. | |
115 | ||
116 | SS_Signal* get_signal() | |
117 | { | |
118 | // There is always one SS_Signal on an empty queue. On a non empty queue | |
119 | // the SS_Signal after the head is the one we are interested in. | |
120 | ||
121 | SS_Signal* temp = head; | |
122 | SS_Signal* help = temp->next; | |
123 | head = help; | |
124 | assert(help); | |
125 | bl_atomic_add32((int32_t*)&flag.signal,-1); | |
126 | temp->next = free_list; | |
127 | temp->type = SS_Signal::FREE; | |
128 | free_list = temp; | |
129 | ++free_count; | |
130 | if (free_count >= free_count_max) | |
131 | { | |
132 | SS_Signal* h = free_list; | |
133 | for (temp = free_list->next; | |
134 | free_count > free_count_max/2; | |
135 | free_list = temp) | |
136 | { | |
137 | assert(free_list->type == SS_Signal::FREE); | |
138 | assert(free_count > 0); | |
139 | --free_count; | |
140 | temp = free_list->next; | |
141 | } | |
142 | SS_Signal* t = free_list; | |
143 | free_list = t->next; | |
144 | assert(free_count > 0); | |
145 | --free_count; | |
146 | SS_Signal::list_free(h, t); | |
147 | } | |
148 | ||
149 | return help; | |
150 | } | |
151 | ||
152 | // make_signal() creates a new signal that can be posted to a strand. | |
153 | // This class maintains it's own pool of signals for MP scalability | |
154 | // reasons. | |
155 | ||
156 | SS_Signal* make_signal( SS_Signal::Type type ) | |
157 | { | |
158 | SS_Signal* help = free_list; | |
159 | if (help == 0) | |
160 | { | |
161 | assert(free_count == 0); | |
162 | return SS_Signal::alloc(type); | |
163 | } | |
164 | else | |
165 | { | |
166 | assert(free_count > 0); | |
167 | --free_count; | |
168 | } | |
169 | free_list = help->next; | |
170 | help->init(type); | |
171 | return help; | |
172 | } | |
173 | ||
174 | void snapshot( SS_SnapShot& ss, const char* prefix ); | |
175 | ||
176 | private: | |
177 | BL_Mutex mutex; | |
178 | ||
179 | // The Flags structure holds all fast but not MP safe flags. These | |
180 | // can only be set by the strand itself. The signal flag is used | |
181 | // for the MP safe SS_Signal based list. | |
182 | ||
183 | struct Flags | |
184 | { | |
185 | uint8_t reenterloop; // Get out of tight loop and reenter | |
186 | uint8_t trap_type; // Handle (disrupting) trap on th next step | |
187 | uint8_t spare[2]; // Reserved for future fast lock free flags | |
188 | int32_t signal; // Used to count number SS_Signals pending | |
189 | }; | |
190 | ||
191 | union | |
192 | { | |
193 | uint64_t pending; // One 8 byte load to test all the flags | |
194 | Flags flag; // The flags for fast messages | |
195 | }; | |
196 | ||
197 | // The signal queue always has a valid head and tail pointer. | |
198 | ||
199 | SS_Signal* head; // Head of the message queue | |
200 | SS_Signal* tail; // Tail of the message queue | |
201 | SS_Signal* free_list; // Free list of signals | |
202 | uint_t free_count; // Nr signals on free list | |
203 | static const uint_t free_count_max = 1024; | |
204 | }; | |
205 | ||
206 | #endif |