File: data_pipe.h

package info (click to toggle)
chromium 135.0.7049.95-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,959,392 kB
  • sloc: cpp: 34,198,526; ansic: 7,100,035; javascript: 3,985,800; python: 1,395,489; asm: 896,754; xml: 722,891; pascal: 180,504; sh: 94,909; perl: 88,388; objc: 79,739; sql: 53,020; cs: 41,358; fortran: 24,137; makefile: 22,501; php: 13,699; tcl: 10,142; yacc: 8,822; ruby: 7,350; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; awk: 197; sed: 36
file content (291 lines) | stat: -rw-r--r-- 12,496 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file provides a C++ wrapping around the Mojo C API for data pipes,
// replacing the prefix of "Mojo" with a "mojo" namespace, and using more
// strongly-typed representations of |MojoHandle|s.
//
// Please see "mojo/public/c/system/data_pipe.h" for complete documentation of
// the API.

#ifndef MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_
#define MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_

#include <stddef.h>
#include <stdint.h>

#include "base/containers/span.h"
#include "base/numerics/safe_conversions.h"
#include "mojo/public/c/system/data_pipe.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/system/handle.h"

namespace mojo {

// A strongly-typed representation of a |MojoHandle| to the producer end of a
// data pipe.
class DataPipeProducerHandle : public Handle {
 public:
  DataPipeProducerHandle() {}
  explicit DataPipeProducerHandle(MojoHandle value) : Handle(value) {}

  // Writes to a data pipe. See |MojoWriteData| for complete documentation.
  //
  // `data` points to the buffer with the data to write.  `data` bigger than
  // 2^32 bytes may result in `MOJO_RESULT_INVALID_ARGUMENT` unless
  // `MojoCreateDataPipeOptions::element_num_bytes` is 1.
  //
  // `bytes_written` is an out parameter that on `MOJO_RESULT_OK` communicates
  // how many bytes (from the beginning of `data`) were actually written into
  // the mojo data pipe (depending on the size of the internal pipe buffer, this
  // may be less than `data.size()`).
  //
  // Note that instead of passing specific `flags`, a more direct method can be
  // used instead:
  // - `MOJO_WRITE_DATA_FLAG_ALL_OR_NONE` => `WriteAllData`
  MojoResult WriteData(base::span<const uint8_t> data,
                       MojoWriteDataFlags flags,
                       size_t& bytes_written) const {
    MojoWriteDataOptions options;
    options.struct_size = sizeof(options);
    options.flags = flags;

    // Because of ABI-stability requirements, the C-level APIs take `uint32_t`.
    // But, for compatibility with C++ containers, the C++ APIs take `size_t`.
    //
    // We use `saturated_cast` so that when `num_bytes` doesn't fit into
    // `uint32_t`, then we will simply report that a smaller number of bytes was
    // written.  We accept that `num_bytes_u32` may no longer being a multiple
    // of `MojoCreateDataPipeOptions::element_num_bytes` and rely on the C layer
    // to return `MOJO_RESULT_INVALID_ARGUMENT` in this case (as reflected in
    // the doc comment above).
    uint32_t num_bytes_u32 = base::saturated_cast<uint32_t>(data.size());

    MojoResult result =
        MojoWriteData(value(), data.data(), &num_bytes_u32, &options);
    bytes_written = size_t{num_bytes_u32};
    return result;
  }

  MojoResult WriteAllData(base::span<const uint8_t> data) const {
    // Ok to ignore `bytes_written` because `MOJO_WRITE_DATA_FLAG_ALL_OR_NONE`
    // means that `MOJO_RESULT_OK` will be returned only if exactly
    // `data.size()` bytes have been written (i.e. if `data.size() ==
    // bytes_written`).
    size_t bytes_written = 0;
    return WriteData(data, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE, bytes_written);
  }

  // Using `kNoSizeHint` as `write_size_hint` argument of `BeginWriteData`
  // conveys that the caller doesn't know (or care) how much data needs to be
  // written into the buffer.
  static constexpr size_t kNoSizeHint = 0;

  // Begins a two-phase write to a data pipe. See |MojoBeginWriteData()| for
  // complete documentation.
  //
  // `buffer` is an out parameter that on `MOJO_RESULT_OK` points to a mutable,
  // pipe-owned buffer, that the caller can write into.  The caller should
  // call `EndWriteData` when they are done writing into the `buffer`.
  MojoResult BeginWriteData(size_t write_size_hint,
                            MojoBeginWriteDataFlags flags,
                            base::span<uint8_t>& buffer) const {
    MojoBeginWriteDataOptions options;
    options.struct_size = sizeof(options);
    options.flags = flags;

    // Because of ABI-stability requirements, the C-level APIs take `uint32_t`.
    // But, for compatibility with C++ containers, the C++ APIs take `size_t`.
    //
    // As documented by MojoBeginWriteData, on input `write_size_hint` is
    // merely a hint of how many bytes the producer is readily able to supply.
    // Therefore we use a `saturated_cast` to gracefully handle big values.
    void* buffer_ptr = nullptr;
    uint32_t buffer_num_bytes = base::saturated_cast<uint32_t>(write_size_hint);
    MojoResult result =
        MojoBeginWriteData(value(), &options, &buffer_ptr, &buffer_num_bytes);
    if (result == MOJO_RESULT_OK) {
      // SAFETY: Relying on the contract of the `MojoBeginWriteData` C API which
      // says: "On success |*buffer| will be a pointer to which the caller can
      // write up to |*buffer_num_bytes| bytes of data."
      buffer = UNSAFE_BUFFERS(base::span(static_cast<uint8_t*>(buffer_ptr),
                                         size_t{buffer_num_bytes}));
    }
    return result;
  }

  // Completes a two-phase write to a data pipe. See |MojoEndWriteData()| for
  // complete documentation.
  MojoResult EndWriteData(size_t num_bytes_written) const {
    if (!base::IsValueInRangeForNumericType<uint32_t>(num_bytes_written))
        [[unlikely]] {
      return MOJO_RESULT_INVALID_ARGUMENT;
    }
    uint32_t num_bytes_written_u32 =
        base::checked_cast<uint32_t>(num_bytes_written);

    return MojoEndWriteData(value(), num_bytes_written_u32, nullptr);
  }

  // Copying and assignment allowed.
};

static_assert(sizeof(DataPipeProducerHandle) == sizeof(Handle),
              "Bad size for C++ DataPipeProducerHandle");

typedef ScopedHandleBase<DataPipeProducerHandle> ScopedDataPipeProducerHandle;
static_assert(sizeof(ScopedDataPipeProducerHandle) ==
                  sizeof(DataPipeProducerHandle),
              "Bad size for C++ ScopedDataPipeProducerHandle");

// A strongly-typed representation of a |MojoHandle| to the consumer end of a
// data pipe.
class DataPipeConsumerHandle : public Handle {
 public:
  DataPipeConsumerHandle() {}
  explicit DataPipeConsumerHandle(MojoHandle value) : Handle(value) {}

  // Reads from a data pipe. See |MojoReadData()| for complete documentation.
  //
  // `buffer` points to the buffer where `ReadData` should copy the read bytes.
  //
  // `bytes_read` is an out parameter that on `MOJO_RESULT_OK` communicates how
  // many bytes (at the beginning of `buffer`) were actually read (depending on
  // the size of the internal pipe buffer, this may be less than
  // `buffer.size()`).
  //
  // Note that instead of passing specific `flags`, a more direct method can be
  // used instead:
  // - `MOJO_READ_DATA_FLAG_DISCARD` => `DiscardData`
  MojoResult ReadData(MojoReadDataFlags flags,
                      base::span<uint8_t> buffer,
                      size_t& bytes_read) const {
    MojoReadDataOptions options;
    options.struct_size = sizeof(options);
    options.flags = flags;

    // Because of ABI-stability requirements, the C-level APIs take `uint32_t`.
    // But, for compatibility with C++ containers, the C++ APIs take `size_t`.
    //
    // Input value of `*num_bytes` is ignored in `MOJO_READ_DATA_FLAG_QUERY`
    // mode and otherwise is an _upper_ bound on how many bytes will be read (or
    // discarded in `MOJO_READ_DATA_FLAG_DISCARD`).  Therefore it is okay to use
    // `saturated_cast` instead of `checked_cast` because the C-layer mojo code
    // will anyway read only up to uin32_t max bytes.
    uint32_t num_bytes = base::saturated_cast<uint32_t>(buffer.size());
    MojoResult result =
        MojoReadData(value(), &options, buffer.data(), &num_bytes);
    bytes_read = size_t{num_bytes};
    return result;
  }

  // Discards data from a data pipe. See |MojoReadData()| and
  // |MOJO_READ_DATA_FLAG_DISCARD| for complete documentation.
  //
  // `bytes_to_discard` is an input parameter that specifies how many bytes from
  // the pipe should be read and discarded.
  //
  // `bytes_discarded` is an output parameter that on `MOJO_RESULT_OK` specifies
  // how many bytes were actually discarded.
  MojoResult DiscardData(size_t bytes_to_discard,
                         size_t& bytes_discarded) const {
    MojoReadDataOptions options;
    options.struct_size = sizeof(options);
    options.flags = MOJO_READ_DATA_FLAG_DISCARD;

    // Because of ABI-stability requirements, the C-level APIs take `uint32_t`.
    // But, for compatibility with C++ containers, the C++ APIs take `size_t`.
    //
    // Since the underlying C-API can always discard less bytes than requested,
    // we can use `saturated_cast` below.
    uint32_t num_bytes = base::saturated_cast<uint32_t>(bytes_to_discard);
    MojoResult result = MojoReadData(value(), &options, nullptr, &num_bytes);
    bytes_discarded = size_t{num_bytes};
    return result;
  }

  // Begins a two-phase read from a data pipe. See |MojoBeginReadData()| for
  // complete documentation.
  //
  // `buffer` is an out parameter that on `MOJO_RESULT_OK` points to a
  // read-only, pipe-owned buffer, that the caller can read from.  The caller
  // should call `EndReadData` when they are done reading from the `buffer`.
  MojoResult BeginReadData(MojoBeginReadDataFlags flags,
                           base::span<const uint8_t>& buffer) const {
    MojoBeginReadDataOptions options;
    options.struct_size = sizeof(options);
    options.flags = flags;

    const void* data = nullptr;
    uint32_t buffer_num_bytes = 0;
    MojoResult result =
        MojoBeginReadData(value(), &options, &data, &buffer_num_bytes);
    if (result == MOJO_RESULT_OK) {
      // SAFETY: Relying on the contract of the `MojoBeginReadData` C API which
      // says: "On success, |*buffer| will be a pointer from which the caller
      // can read up to |*buffer_num_bytes| bytes of data."
      buffer = UNSAFE_BUFFERS(base::span(static_cast<const uint8_t*>(data),
                                         size_t{buffer_num_bytes}));
    }
    return result;
  }

  // Completes a two-phase read from a data pipe. See |MojoEndReadData()| for
  // complete documentation.
  MojoResult EndReadData(size_t num_bytes_read) const {
    if (!base::IsValueInRangeForNumericType<uint32_t>(num_bytes_read))
        [[unlikely]] {
      return MOJO_RESULT_INVALID_ARGUMENT;
    }
    uint32_t num_bytes_read_u32 = base::checked_cast<uint32_t>(num_bytes_read);

    return MojoEndReadData(value(), num_bytes_read_u32, nullptr);
  }

  // Copying and assignment allowed.
};

static_assert(sizeof(DataPipeConsumerHandle) == sizeof(Handle),
              "Bad size for C++ DataPipeConsumerHandle");

typedef ScopedHandleBase<DataPipeConsumerHandle> ScopedDataPipeConsumerHandle;
static_assert(sizeof(ScopedDataPipeConsumerHandle) ==
                  sizeof(DataPipeConsumerHandle),
              "Bad size for C++ ScopedDataPipeConsumerHandle");

// Creates a new data pipe. See |MojoCreateDataPipe()| for complete
// documentation.
inline MojoResult CreateDataPipe(
    const MojoCreateDataPipeOptions* options,
    ScopedDataPipeProducerHandle& data_pipe_producer,
    ScopedDataPipeConsumerHandle& data_pipe_consumer) {
  DataPipeProducerHandle producer_handle;
  DataPipeConsumerHandle consumer_handle;
  MojoResult rv = MojoCreateDataPipe(options,
                                     producer_handle.mutable_value(),
                                     consumer_handle.mutable_value());
  // Reset even on failure (reduces the chances that a "stale"/incorrect handle
  // will be used).
  data_pipe_producer.reset(producer_handle);
  data_pipe_consumer.reset(consumer_handle);
  return rv;
}

// Creates a new data pipe with a specified capacity size. For setting
// additional options, see |CreateDataPipe()| above.
inline MojoResult CreateDataPipe(
    uint32_t capacity_num_bytes,
    ScopedDataPipeProducerHandle& data_pipe_producer,
    ScopedDataPipeConsumerHandle& data_pipe_consumer) {
  MojoCreateDataPipeOptions options;
  options.struct_size = sizeof(MojoCreateDataPipeOptions);
  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
  options.element_num_bytes = 1;
  options.capacity_num_bytes = capacity_num_bytes;
  return CreateDataPipe(&options, data_pipe_producer, data_pipe_consumer);
}

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_H_