| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "mojo/edk/system/data_pipe.h" | |
| 6 | |
| 7 #include <string.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <limits> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "mojo/edk/system/awakable_list.h" | |
| 14 #include "mojo/edk/system/configuration.h" | |
| 15 #include "mojo/edk/system/memory.h" | |
| 16 #include "mojo/edk/system/options_validation.h" | |
| 17 | |
| 18 namespace mojo { | |
| 19 namespace system { | |
| 20 | |
| 21 // static | |
| 22 MojoCreateDataPipeOptions DataPipe::GetDefaultCreateOptions() { | |
| 23 MojoCreateDataPipeOptions result = { | |
| 24 static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)), | |
| 25 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, | |
| 26 1u, | |
| 27 static_cast<uint32_t>( | |
| 28 GetConfiguration().default_data_pipe_capacity_bytes)}; | |
| 29 return result; | |
| 30 } | |
| 31 | |
| 32 // static | |
| 33 MojoResult DataPipe::ValidateCreateOptions( | |
| 34 UserPointer<const MojoCreateDataPipeOptions> in_options, | |
| 35 MojoCreateDataPipeOptions* out_options) { | |
| 36 const MojoCreateDataPipeOptionsFlags kKnownFlags = | |
| 37 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD; | |
| 38 | |
| 39 *out_options = GetDefaultCreateOptions(); | |
| 40 if (in_options.IsNull()) | |
| 41 return MOJO_RESULT_OK; | |
| 42 | |
| 43 UserOptionsReader<MojoCreateDataPipeOptions> reader(in_options); | |
| 44 if (!reader.is_valid()) | |
| 45 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 46 | |
| 47 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, flags, reader)) | |
| 48 return MOJO_RESULT_OK; | |
| 49 if ((reader.options().flags & ~kKnownFlags)) | |
| 50 return MOJO_RESULT_UNIMPLEMENTED; | |
| 51 out_options->flags = reader.options().flags; | |
| 52 | |
| 53 // Checks for fields beyond |flags|: | |
| 54 | |
| 55 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, element_num_bytes, | |
| 56 reader)) | |
| 57 return MOJO_RESULT_OK; | |
| 58 if (reader.options().element_num_bytes == 0) | |
| 59 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 60 out_options->element_num_bytes = reader.options().element_num_bytes; | |
| 61 | |
| 62 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, capacity_num_bytes, | |
| 63 reader) || | |
| 64 reader.options().capacity_num_bytes == 0) { | |
| 65 // Round the default capacity down to a multiple of the element size (but at | |
| 66 // least one element). | |
| 67 size_t default_data_pipe_capacity_bytes = | |
| 68 GetConfiguration().default_data_pipe_capacity_bytes; | |
| 69 out_options->capacity_num_bytes = | |
| 70 std::max(static_cast<uint32_t>(default_data_pipe_capacity_bytes - | |
| 71 (default_data_pipe_capacity_bytes % | |
| 72 out_options->element_num_bytes)), | |
| 73 out_options->element_num_bytes); | |
| 74 return MOJO_RESULT_OK; | |
| 75 } | |
| 76 if (reader.options().capacity_num_bytes % out_options->element_num_bytes != 0) | |
| 77 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 78 if (reader.options().capacity_num_bytes > | |
| 79 GetConfiguration().max_data_pipe_capacity_bytes) | |
| 80 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
| 81 out_options->capacity_num_bytes = reader.options().capacity_num_bytes; | |
| 82 | |
| 83 return MOJO_RESULT_OK; | |
| 84 } | |
| 85 | |
| 86 void DataPipe::ProducerCancelAllAwakables() { | |
| 87 base::AutoLock locker(lock_); | |
| 88 DCHECK(has_local_producer_no_lock()); | |
| 89 producer_awakable_list_->CancelAll(); | |
| 90 } | |
| 91 | |
| 92 void DataPipe::ProducerClose() { | |
| 93 base::AutoLock locker(lock_); | |
| 94 DCHECK(producer_open_); | |
| 95 producer_open_ = false; | |
| 96 DCHECK(has_local_producer_no_lock()); | |
| 97 producer_awakable_list_.reset(); | |
| 98 // Not a bug, except possibly in "user" code. | |
| 99 DVLOG_IF(2, producer_in_two_phase_write_no_lock()) | |
| 100 << "Producer closed with active two-phase write"; | |
| 101 producer_two_phase_max_num_bytes_written_ = 0; | |
| 102 ProducerCloseImplNoLock(); | |
| 103 AwakeConsumerAwakablesForStateChangeNoLock( | |
| 104 ConsumerGetHandleSignalsStateImplNoLock()); | |
| 105 } | |
| 106 | |
| 107 MojoResult DataPipe::ProducerWriteData(UserPointer<const void> elements, | |
| 108 UserPointer<uint32_t> num_bytes, | |
| 109 bool all_or_none) { | |
| 110 base::AutoLock locker(lock_); | |
| 111 DCHECK(has_local_producer_no_lock()); | |
| 112 | |
| 113 if (producer_in_two_phase_write_no_lock()) | |
| 114 return MOJO_RESULT_BUSY; | |
| 115 if (!consumer_open_no_lock()) | |
| 116 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 117 | |
| 118 // Returning "busy" takes priority over "invalid argument". | |
| 119 uint32_t max_num_bytes_to_write = num_bytes.Get(); | |
| 120 if (max_num_bytes_to_write % element_num_bytes_ != 0) | |
| 121 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 122 | |
| 123 if (max_num_bytes_to_write == 0) | |
| 124 return MOJO_RESULT_OK; // Nothing to do. | |
| 125 | |
| 126 uint32_t min_num_bytes_to_write = all_or_none ? max_num_bytes_to_write : 0; | |
| 127 | |
| 128 HandleSignalsState old_consumer_state = | |
| 129 ConsumerGetHandleSignalsStateImplNoLock(); | |
| 130 MojoResult rv = ProducerWriteDataImplNoLock( | |
| 131 elements, num_bytes, max_num_bytes_to_write, min_num_bytes_to_write); | |
| 132 HandleSignalsState new_consumer_state = | |
| 133 ConsumerGetHandleSignalsStateImplNoLock(); | |
| 134 if (!new_consumer_state.equals(old_consumer_state)) | |
| 135 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); | |
| 136 return rv; | |
| 137 } | |
| 138 | |
| 139 MojoResult DataPipe::ProducerBeginWriteData( | |
| 140 UserPointer<void*> buffer, | |
| 141 UserPointer<uint32_t> buffer_num_bytes, | |
| 142 bool all_or_none) { | |
| 143 base::AutoLock locker(lock_); | |
| 144 DCHECK(has_local_producer_no_lock()); | |
| 145 | |
| 146 if (producer_in_two_phase_write_no_lock()) | |
| 147 return MOJO_RESULT_BUSY; | |
| 148 if (!consumer_open_no_lock()) | |
| 149 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 150 | |
| 151 uint32_t min_num_bytes_to_write = 0; | |
| 152 if (all_or_none) { | |
| 153 min_num_bytes_to_write = buffer_num_bytes.Get(); | |
| 154 if (min_num_bytes_to_write % element_num_bytes_ != 0) | |
| 155 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 156 } | |
| 157 | |
| 158 MojoResult rv = ProducerBeginWriteDataImplNoLock(buffer, buffer_num_bytes, | |
| 159 min_num_bytes_to_write); | |
| 160 if (rv != MOJO_RESULT_OK) | |
| 161 return rv; | |
| 162 // Note: No need to awake producer awakables, even though we're going from | |
| 163 // writable to non-writable (since you can't wait on non-writability). | |
| 164 // Similarly, though this may have discarded data (in "may discard" mode), | |
| 165 // making it non-readable, there's still no need to awake consumer awakables. | |
| 166 DCHECK(producer_in_two_phase_write_no_lock()); | |
| 167 return MOJO_RESULT_OK; | |
| 168 } | |
| 169 | |
| 170 MojoResult DataPipe::ProducerEndWriteData(uint32_t num_bytes_written) { | |
| 171 base::AutoLock locker(lock_); | |
| 172 DCHECK(has_local_producer_no_lock()); | |
| 173 | |
| 174 if (!producer_in_two_phase_write_no_lock()) | |
| 175 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 176 // Note: Allow successful completion of the two-phase write even if the | |
| 177 // consumer has been closed. | |
| 178 | |
| 179 HandleSignalsState old_consumer_state = | |
| 180 ConsumerGetHandleSignalsStateImplNoLock(); | |
| 181 MojoResult rv; | |
| 182 if (num_bytes_written > producer_two_phase_max_num_bytes_written_ || | |
| 183 num_bytes_written % element_num_bytes_ != 0) { | |
| 184 rv = MOJO_RESULT_INVALID_ARGUMENT; | |
| 185 producer_two_phase_max_num_bytes_written_ = 0; | |
| 186 } else { | |
| 187 rv = ProducerEndWriteDataImplNoLock(num_bytes_written); | |
| 188 } | |
| 189 // Two-phase write ended even on failure. | |
| 190 DCHECK(!producer_in_two_phase_write_no_lock()); | |
| 191 // If we're now writable, we *became* writable (since we weren't writable | |
| 192 // during the two-phase write), so awake producer awakables. | |
| 193 HandleSignalsState new_producer_state = | |
| 194 ProducerGetHandleSignalsStateImplNoLock(); | |
| 195 if (new_producer_state.satisfies(MOJO_HANDLE_SIGNAL_WRITABLE)) | |
| 196 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); | |
| 197 HandleSignalsState new_consumer_state = | |
| 198 ConsumerGetHandleSignalsStateImplNoLock(); | |
| 199 if (!new_consumer_state.equals(old_consumer_state)) | |
| 200 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); | |
| 201 return rv; | |
| 202 } | |
| 203 | |
| 204 HandleSignalsState DataPipe::ProducerGetHandleSignalsState() { | |
| 205 base::AutoLock locker(lock_); | |
| 206 DCHECK(has_local_producer_no_lock()); | |
| 207 return ProducerGetHandleSignalsStateImplNoLock(); | |
| 208 } | |
| 209 | |
| 210 MojoResult DataPipe::ProducerAddAwakable(Awakable* awakable, | |
| 211 MojoHandleSignals signals, | |
| 212 uint32_t context, | |
| 213 HandleSignalsState* signals_state) { | |
| 214 base::AutoLock locker(lock_); | |
| 215 DCHECK(has_local_producer_no_lock()); | |
| 216 | |
| 217 HandleSignalsState producer_state = ProducerGetHandleSignalsStateImplNoLock(); | |
| 218 if (producer_state.satisfies(signals)) { | |
| 219 if (signals_state) | |
| 220 *signals_state = producer_state; | |
| 221 return MOJO_RESULT_ALREADY_EXISTS; | |
| 222 } | |
| 223 if (!producer_state.can_satisfy(signals)) { | |
| 224 if (signals_state) | |
| 225 *signals_state = producer_state; | |
| 226 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 227 } | |
| 228 | |
| 229 producer_awakable_list_->Add(awakable, signals, context); | |
| 230 return MOJO_RESULT_OK; | |
| 231 } | |
| 232 | |
| 233 void DataPipe::ProducerRemoveAwakable(Awakable* awakable, | |
| 234 HandleSignalsState* signals_state) { | |
| 235 base::AutoLock locker(lock_); | |
| 236 DCHECK(has_local_producer_no_lock()); | |
| 237 producer_awakable_list_->Remove(awakable); | |
| 238 if (signals_state) | |
| 239 *signals_state = ProducerGetHandleSignalsStateImplNoLock(); | |
| 240 } | |
| 241 | |
| 242 bool DataPipe::ProducerIsBusy() const { | |
| 243 base::AutoLock locker(lock_); | |
| 244 return producer_in_two_phase_write_no_lock(); | |
| 245 } | |
| 246 | |
| 247 void DataPipe::ConsumerCancelAllAwakables() { | |
| 248 base::AutoLock locker(lock_); | |
| 249 DCHECK(has_local_consumer_no_lock()); | |
| 250 consumer_awakable_list_->CancelAll(); | |
| 251 } | |
| 252 | |
| 253 void DataPipe::ConsumerClose() { | |
| 254 base::AutoLock locker(lock_); | |
| 255 DCHECK(consumer_open_); | |
| 256 consumer_open_ = false; | |
| 257 DCHECK(has_local_consumer_no_lock()); | |
| 258 consumer_awakable_list_.reset(); | |
| 259 // Not a bug, except possibly in "user" code. | |
| 260 DVLOG_IF(2, consumer_in_two_phase_read_no_lock()) | |
| 261 << "Consumer closed with active two-phase read"; | |
| 262 consumer_two_phase_max_num_bytes_read_ = 0; | |
| 263 ConsumerCloseImplNoLock(); | |
| 264 AwakeProducerAwakablesForStateChangeNoLock( | |
| 265 ProducerGetHandleSignalsStateImplNoLock()); | |
| 266 } | |
| 267 | |
| 268 MojoResult DataPipe::ConsumerReadData(UserPointer<void> elements, | |
| 269 UserPointer<uint32_t> num_bytes, | |
| 270 bool all_or_none, | |
| 271 bool peek) { | |
| 272 base::AutoLock locker(lock_); | |
| 273 DCHECK(has_local_consumer_no_lock()); | |
| 274 | |
| 275 if (consumer_in_two_phase_read_no_lock()) | |
| 276 return MOJO_RESULT_BUSY; | |
| 277 | |
| 278 uint32_t max_num_bytes_to_read = num_bytes.Get(); | |
| 279 if (max_num_bytes_to_read % element_num_bytes_ != 0) | |
| 280 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 281 | |
| 282 if (max_num_bytes_to_read == 0) | |
| 283 return MOJO_RESULT_OK; // Nothing to do. | |
| 284 | |
| 285 uint32_t min_num_bytes_to_read = all_or_none ? max_num_bytes_to_read : 0; | |
| 286 | |
| 287 HandleSignalsState old_producer_state = | |
| 288 ProducerGetHandleSignalsStateImplNoLock(); | |
| 289 MojoResult rv = ConsumerReadDataImplNoLock( | |
| 290 elements, num_bytes, max_num_bytes_to_read, min_num_bytes_to_read, peek); | |
| 291 HandleSignalsState new_producer_state = | |
| 292 ProducerGetHandleSignalsStateImplNoLock(); | |
| 293 if (!new_producer_state.equals(old_producer_state)) | |
| 294 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); | |
| 295 return rv; | |
| 296 } | |
| 297 | |
| 298 MojoResult DataPipe::ConsumerDiscardData(UserPointer<uint32_t> num_bytes, | |
| 299 bool all_or_none) { | |
| 300 base::AutoLock locker(lock_); | |
| 301 DCHECK(has_local_consumer_no_lock()); | |
| 302 | |
| 303 if (consumer_in_two_phase_read_no_lock()) | |
| 304 return MOJO_RESULT_BUSY; | |
| 305 | |
| 306 uint32_t max_num_bytes_to_discard = num_bytes.Get(); | |
| 307 if (max_num_bytes_to_discard % element_num_bytes_ != 0) | |
| 308 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 309 | |
| 310 if (max_num_bytes_to_discard == 0) | |
| 311 return MOJO_RESULT_OK; // Nothing to do. | |
| 312 | |
| 313 uint32_t min_num_bytes_to_discard = | |
| 314 all_or_none ? max_num_bytes_to_discard : 0; | |
| 315 | |
| 316 HandleSignalsState old_producer_state = | |
| 317 ProducerGetHandleSignalsStateImplNoLock(); | |
| 318 MojoResult rv = ConsumerDiscardDataImplNoLock( | |
| 319 num_bytes, max_num_bytes_to_discard, min_num_bytes_to_discard); | |
| 320 HandleSignalsState new_producer_state = | |
| 321 ProducerGetHandleSignalsStateImplNoLock(); | |
| 322 if (!new_producer_state.equals(old_producer_state)) | |
| 323 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); | |
| 324 return rv; | |
| 325 } | |
| 326 | |
| 327 MojoResult DataPipe::ConsumerQueryData(UserPointer<uint32_t> num_bytes) { | |
| 328 base::AutoLock locker(lock_); | |
| 329 DCHECK(has_local_consumer_no_lock()); | |
| 330 | |
| 331 if (consumer_in_two_phase_read_no_lock()) | |
| 332 return MOJO_RESULT_BUSY; | |
| 333 | |
| 334 // Note: Don't need to validate |*num_bytes| for query. | |
| 335 return ConsumerQueryDataImplNoLock(num_bytes); | |
| 336 } | |
| 337 | |
| 338 MojoResult DataPipe::ConsumerBeginReadData( | |
| 339 UserPointer<const void*> buffer, | |
| 340 UserPointer<uint32_t> buffer_num_bytes, | |
| 341 bool all_or_none) { | |
| 342 base::AutoLock locker(lock_); | |
| 343 DCHECK(has_local_consumer_no_lock()); | |
| 344 | |
| 345 if (consumer_in_two_phase_read_no_lock()) | |
| 346 return MOJO_RESULT_BUSY; | |
| 347 | |
| 348 uint32_t min_num_bytes_to_read = 0; | |
| 349 if (all_or_none) { | |
| 350 min_num_bytes_to_read = buffer_num_bytes.Get(); | |
| 351 if (min_num_bytes_to_read % element_num_bytes_ != 0) | |
| 352 return MOJO_RESULT_INVALID_ARGUMENT; | |
| 353 } | |
| 354 | |
| 355 MojoResult rv = ConsumerBeginReadDataImplNoLock(buffer, buffer_num_bytes, | |
| 356 min_num_bytes_to_read); | |
| 357 if (rv != MOJO_RESULT_OK) | |
| 358 return rv; | |
| 359 DCHECK(consumer_in_two_phase_read_no_lock()); | |
| 360 return MOJO_RESULT_OK; | |
| 361 } | |
| 362 | |
| 363 MojoResult DataPipe::ConsumerEndReadData(uint32_t num_bytes_read) { | |
| 364 base::AutoLock locker(lock_); | |
| 365 DCHECK(has_local_consumer_no_lock()); | |
| 366 | |
| 367 if (!consumer_in_two_phase_read_no_lock()) | |
| 368 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 369 | |
| 370 HandleSignalsState old_producer_state = | |
| 371 ProducerGetHandleSignalsStateImplNoLock(); | |
| 372 MojoResult rv; | |
| 373 if (num_bytes_read > consumer_two_phase_max_num_bytes_read_ || | |
| 374 num_bytes_read % element_num_bytes_ != 0) { | |
| 375 rv = MOJO_RESULT_INVALID_ARGUMENT; | |
| 376 consumer_two_phase_max_num_bytes_read_ = 0; | |
| 377 } else { | |
| 378 rv = ConsumerEndReadDataImplNoLock(num_bytes_read); | |
| 379 } | |
| 380 // Two-phase read ended even on failure. | |
| 381 DCHECK(!consumer_in_two_phase_read_no_lock()); | |
| 382 // If we're now readable, we *became* readable (since we weren't readable | |
| 383 // during the two-phase read), so awake consumer awakables. | |
| 384 HandleSignalsState new_consumer_state = | |
| 385 ConsumerGetHandleSignalsStateImplNoLock(); | |
| 386 if (new_consumer_state.satisfies(MOJO_HANDLE_SIGNAL_READABLE)) | |
| 387 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); | |
| 388 HandleSignalsState new_producer_state = | |
| 389 ProducerGetHandleSignalsStateImplNoLock(); | |
| 390 if (!new_producer_state.equals(old_producer_state)) | |
| 391 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); | |
| 392 return rv; | |
| 393 } | |
| 394 | |
| 395 HandleSignalsState DataPipe::ConsumerGetHandleSignalsState() { | |
| 396 base::AutoLock locker(lock_); | |
| 397 DCHECK(has_local_consumer_no_lock()); | |
| 398 return ConsumerGetHandleSignalsStateImplNoLock(); | |
| 399 } | |
| 400 | |
| 401 MojoResult DataPipe::ConsumerAddAwakable(Awakable* awakable, | |
| 402 MojoHandleSignals signals, | |
| 403 uint32_t context, | |
| 404 HandleSignalsState* signals_state) { | |
| 405 base::AutoLock locker(lock_); | |
| 406 DCHECK(has_local_consumer_no_lock()); | |
| 407 | |
| 408 HandleSignalsState consumer_state = ConsumerGetHandleSignalsStateImplNoLock(); | |
| 409 if (consumer_state.satisfies(signals)) { | |
| 410 if (signals_state) | |
| 411 *signals_state = consumer_state; | |
| 412 return MOJO_RESULT_ALREADY_EXISTS; | |
| 413 } | |
| 414 if (!consumer_state.can_satisfy(signals)) { | |
| 415 if (signals_state) | |
| 416 *signals_state = consumer_state; | |
| 417 return MOJO_RESULT_FAILED_PRECONDITION; | |
| 418 } | |
| 419 | |
| 420 consumer_awakable_list_->Add(awakable, signals, context); | |
| 421 return MOJO_RESULT_OK; | |
| 422 } | |
| 423 | |
| 424 void DataPipe::ConsumerRemoveAwakable(Awakable* awakable, | |
| 425 HandleSignalsState* signals_state) { | |
| 426 base::AutoLock locker(lock_); | |
| 427 DCHECK(has_local_consumer_no_lock()); | |
| 428 consumer_awakable_list_->Remove(awakable); | |
| 429 if (signals_state) | |
| 430 *signals_state = ConsumerGetHandleSignalsStateImplNoLock(); | |
| 431 } | |
| 432 | |
| 433 bool DataPipe::ConsumerIsBusy() const { | |
| 434 base::AutoLock locker(lock_); | |
| 435 return consumer_in_two_phase_read_no_lock(); | |
| 436 } | |
| 437 | |
| 438 DataPipe::DataPipe(bool has_local_producer, | |
| 439 bool has_local_consumer, | |
| 440 const MojoCreateDataPipeOptions& validated_options) | |
| 441 : may_discard_((validated_options.flags & | |
| 442 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)), | |
| 443 element_num_bytes_(validated_options.element_num_bytes), | |
| 444 capacity_num_bytes_(validated_options.capacity_num_bytes), | |
| 445 producer_open_(true), | |
| 446 consumer_open_(true), | |
| 447 producer_awakable_list_(has_local_producer ? new AwakableList() | |
| 448 : nullptr), | |
| 449 consumer_awakable_list_(has_local_consumer ? new AwakableList() | |
| 450 : nullptr), | |
| 451 producer_two_phase_max_num_bytes_written_(0), | |
| 452 consumer_two_phase_max_num_bytes_read_(0) { | |
| 453 // Check that the passed in options actually are validated. | |
| 454 MojoCreateDataPipeOptions unused = {0}; | |
| 455 DCHECK_EQ(ValidateCreateOptions(MakeUserPointer(&validated_options), &unused), | |
| 456 MOJO_RESULT_OK); | |
| 457 } | |
| 458 | |
| 459 DataPipe::~DataPipe() { | |
| 460 DCHECK(!producer_open_); | |
| 461 DCHECK(!consumer_open_); | |
| 462 DCHECK(!producer_awakable_list_); | |
| 463 DCHECK(!consumer_awakable_list_); | |
| 464 } | |
| 465 | |
| 466 void DataPipe::AwakeProducerAwakablesForStateChangeNoLock( | |
| 467 const HandleSignalsState& new_producer_state) { | |
| 468 lock_.AssertAcquired(); | |
| 469 if (!has_local_producer_no_lock()) | |
| 470 return; | |
| 471 producer_awakable_list_->AwakeForStateChange(new_producer_state); | |
| 472 } | |
| 473 | |
| 474 void DataPipe::AwakeConsumerAwakablesForStateChangeNoLock( | |
| 475 const HandleSignalsState& new_consumer_state) { | |
| 476 lock_.AssertAcquired(); | |
| 477 if (!has_local_consumer_no_lock()) | |
| 478 return; | |
| 479 consumer_awakable_list_->AwakeForStateChange(new_consumer_state); | |
| 480 } | |
| 481 | |
| 482 } // namespace system | |
| 483 } // namespace mojo | |
| OLD | NEW |