1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <UserEvent.h> 8 9 #include <ksignal.h> 10 #include <thread_types.h> 11 #include <util/AutoLock.h> 12 13 14 // #pragma mark - UserEvent 15 16 17 UserEvent::~UserEvent() 18 { 19 } 20 21 22 // #pragma mark - SignalEvent 23 24 25 struct SignalEvent::EventSignal : Signal { 26 EventSignal(uint32 number, int32 signalCode, int32 errorCode, 27 pid_t sendingProcess) 28 : 29 Signal(number, signalCode, errorCode, sendingProcess), 30 fInUse(false) 31 { 32 } 33 34 bool IsInUse() const 35 { 36 return fInUse; 37 } 38 39 void SetInUse(bool inUse) 40 { 41 fInUse = inUse; 42 } 43 44 virtual void Handled() 45 { 46 // mark not-in-use 47 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 48 fInUse = false; 49 schedulerLocker.Unlock(); 50 51 Signal::Handled(); 52 } 53 54 private: 55 bool fInUse; 56 }; 57 58 59 SignalEvent::SignalEvent(EventSignal* signal) 60 : 61 fSignal(signal) 62 { 63 } 64 65 66 SignalEvent::~SignalEvent() 67 { 68 fSignal->ReleaseReference(); 69 } 70 71 72 void 73 SignalEvent::SetUserValue(union sigval userValue) 74 { 75 fSignal->SetUserValue(userValue); 76 } 77 78 79 // #pragma mark - TeamSignalEvent 80 81 82 TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal) 83 : 84 SignalEvent(signal), 85 fTeam(team) 86 { 87 } 88 89 90 /*static*/ TeamSignalEvent* 91 TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode, 92 int32 errorCode) 93 { 94 // create the signal 95 EventSignal* signal = new(std::nothrow) EventSignal(signalNumber, 96 signalCode, errorCode, team->id); 97 if (signal == NULL) 98 return NULL; 99 100 // create the event 101 TeamSignalEvent* event = new TeamSignalEvent(team, signal); 102 if (event == NULL) { 103 delete signal; 104 return NULL; 105 } 106 107 return event; 108 } 109 110 111 status_t 112 TeamSignalEvent::Fire() 113 { 114 // called with the scheduler lock held 115 if (fSignal->IsInUse()) 116 return B_BUSY; 117 118 fSignal->AcquireReference(); 119 // one reference is transferred to send_signal_to_team_locked 120 status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(), 121 fSignal, B_DO_NOT_RESCHEDULE); 122 if (error == B_OK) { 123 // Mark the signal in-use. There are situations (for certain signals), 124 // in which send_signal_to_team_locked() succeeds without queuing the 125 // signal. 126 fSignal->SetInUse(fSignal->IsPending()); 127 } 128 129 return error; 130 } 131 132 133 // #pragma mark - ThreadSignalEvent 134 135 136 ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal) 137 : 138 SignalEvent(signal), 139 fThread(thread) 140 { 141 } 142 143 144 /*static*/ ThreadSignalEvent* 145 ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode, 146 int32 errorCode, pid_t sendingTeam) 147 { 148 // create the signal 149 EventSignal* signal = new(std::nothrow) EventSignal(signalNumber, 150 signalCode, errorCode, sendingTeam); 151 if (signal == NULL) 152 return NULL; 153 154 // create the event 155 ThreadSignalEvent* event = new ThreadSignalEvent(thread, signal); 156 if (event == NULL) { 157 delete signal; 158 return NULL; 159 } 160 161 return event; 162 } 163 164 165 status_t 166 ThreadSignalEvent::Fire() 167 { 168 // called with the scheduler lock held 169 if (fSignal->IsInUse()) 170 return B_BUSY; 171 172 fSignal->AcquireReference(); 173 // one reference is transferred to send_signal_to_team_locked 174 status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(), 175 fSignal, B_DO_NOT_RESCHEDULE); 176 if (error == B_OK) { 177 // Mark the signal in-use. There are situations (for certain signals), 178 // in which send_signal_to_team_locked() succeeds without queuing the 179 // signal. 180 fSignal->SetInUse(fSignal->IsPending()); 181 } 182 183 return error; 184 } 185 186 187 // #pragma mark - UserEvent 188 189 190 CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes) 191 : 192 fCreationAttributes(attributes), 193 fPendingDPC(false) 194 { 195 // attributes.name is a pointer to a temporary buffer. Copy the name into 196 // our own buffer and replace the name pointer. 197 strlcpy(fThreadName, attributes.name, sizeof(fThreadName)); 198 fCreationAttributes.name = fThreadName; 199 } 200 201 202 CreateThreadEvent::~CreateThreadEvent() 203 { 204 // cancel the DPC to be on the safe side 205 DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Cancel(this); 206 } 207 208 209 /*static*/ CreateThreadEvent* 210 CreateThreadEvent::Create(const ThreadCreationAttributes& attributes) 211 { 212 return new(std::nothrow) CreateThreadEvent(attributes); 213 } 214 215 216 status_t 217 CreateThreadEvent::Fire() 218 { 219 if (fPendingDPC) 220 return B_BUSY; 221 222 fPendingDPC = true; 223 224 DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true); 225 226 return B_OK; 227 } 228 229 230 void 231 CreateThreadEvent::DoDPC(DPCQueue* queue) 232 { 233 // We're no longer queued in the DPC queue, so we can be reused. 234 { 235 InterruptsSpinLocker schedulerLocker(gSchedulerLock); 236 fPendingDPC = false; 237 } 238 239 // create the thread 240 thread_id threadID = thread_create_thread(fCreationAttributes, false); 241 if (threadID >= 0) 242 resume_thread(threadID); 243 } 244