File: dispatch_source_unittest.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (184 lines) | stat: -rw-r--r-- 5,276 bytes parent folder | download | duplicates (5)
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
// 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.

#include "base/apple/dispatch_source.h"

#include <mach/mach.h>

#include <memory>

#include "base/apple/scoped_mach_port.h"
#include "base/logging.h"
#include "base/test/test_timeouts.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base::apple {

#if !BUILDFLAG(IS_IOS_TVOS)
class DispatchSourceTest : public testing::Test {
 public:
  void SetUp() override {
    mach_port_t port = MACH_PORT_NULL;
    ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
                                               MACH_PORT_RIGHT_RECEIVE, &port));
    receive_right_.reset(port);

    ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(mach_task_self(), port, port,
                                                   MACH_MSG_TYPE_MAKE_SEND));
    send_right_.reset(port);
  }

  mach_port_t GetPort() { return receive_right_.get(); }

  void WaitForSemaphore(dispatch_semaphore_t semaphore) {
    dispatch_semaphore_wait(
        semaphore, dispatch_time(DISPATCH_TIME_NOW,
                                 TestTimeouts::action_timeout().InSeconds() *
                                     NSEC_PER_SEC));
  }

 private:
  base::apple::ScopedMachReceiveRight receive_right_;
  base::apple::ScopedMachSendRight send_right_;
};

TEST_F(DispatchSourceTest, ReceiveAfterResume) {
  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
  mach_port_t port = GetPort();

  bool __block did_receive = false;
  DispatchSource source("org.chromium.base.test.ReceiveAfterResume", port, ^{
    mach_msg_empty_rcv_t msg = {{0}};
    msg.header.msgh_size = sizeof(msg);
    msg.header.msgh_local_port = port;
    mach_msg_receive(&msg.header);
    did_receive = true;

    dispatch_semaphore_signal(signal);
  });

  mach_msg_empty_send_t msg = {{0}};
  msg.header.msgh_size = sizeof(msg);
  msg.header.msgh_remote_port = port;
  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
  ASSERT_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));

  EXPECT_FALSE(did_receive);

  source.Resume();

  WaitForSemaphore(signal);
  dispatch_release(signal);

  EXPECT_TRUE(did_receive);
}

TEST_F(DispatchSourceTest, NoMessagesAfterDestruction) {
  mach_port_t port = GetPort();

  std::unique_ptr<int> count(new int(0));
  int* __block count_ptr = count.get();

  std::unique_ptr<DispatchSource> source(new DispatchSource(
      "org.chromium.base.test.NoMessagesAfterDestruction", port, ^{
        mach_msg_empty_rcv_t msg = {{0}};
        msg.header.msgh_size = sizeof(msg);
        msg.header.msgh_local_port = port;
        mach_msg_receive(&msg.header);
        LOG(INFO) << "Receive " << *count_ptr;
        ++(*count_ptr);
      }));
  source->Resume();

  dispatch_queue_t queue =
      dispatch_queue_create("org.chromium.base.test.MessageSend", NULL);
  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
  for (int i = 0; i < 30; ++i) {
    dispatch_async(queue, ^{
      mach_msg_empty_send_t msg = {{0}};
      msg.header.msgh_size = sizeof(msg);
      msg.header.msgh_remote_port = port;
      msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
      mach_msg_send(&msg.header);
    });

    // After sending five messages, shut down the source and taint the
    // pointer the handler dereferences. The test will crash if |count_ptr|
    // is being used after "free".
    if (i == 5) {
      std::unique_ptr<DispatchSource>* source_ptr = &source;
      dispatch_async(queue, ^{
        source_ptr->reset();
        count_ptr = reinterpret_cast<int*>(0xdeaddead);
        dispatch_semaphore_signal(signal);
      });
    }
  }

  WaitForSemaphore(signal);
  dispatch_release(signal);

  dispatch_release(queue);
}
#endif

class DispatchSourceFdTest : public testing::Test {
 public:
  void SetUp() override {
    /* Create the pipe. */
    ASSERT_EQ(KERN_SUCCESS, pipe(pipe_fds_));
  }

  int GetWrite() { return pipe_fds_[1]; }
  int GetRead() { return pipe_fds_[0]; }

  void WaitForSemaphore(dispatch_semaphore_t semaphore) {
    dispatch_semaphore_wait(
        semaphore, dispatch_time(DISPATCH_TIME_NOW,
                                 TestTimeouts::action_timeout().InSeconds() *
                                     NSEC_PER_SEC));
  }

 private:
  int pipe_fds_[2];
};

TEST_F(DispatchSourceFdTest, ReceiveAfterResume) {
  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
  dispatch_queue_t queue = dispatch_queue_create(
      "org.chromium.base.test.ReceiveAfterResume", DISPATCH_QUEUE_SERIAL);
  int read_fd = GetRead();

  bool __block did_receive = false;
  DispatchSource source(queue, read_fd, DISPATCH_SOURCE_TYPE_READ, ^{
    char buf[1];
    ASSERT_EQ(read(read_fd, &buf, 1), 1);
    did_receive = true;

    dispatch_semaphore_signal(signal);
  });

  int write_fd = GetWrite();
  ASSERT_EQ(write(write_fd, "1", 1), 1);

  EXPECT_FALSE(did_receive);

  source.Resume();

  WaitForSemaphore(signal);

  EXPECT_TRUE(did_receive);

  source.Suspend();
  did_receive = false;
  ASSERT_EQ(write(write_fd, "2", 1), 1);
  EXPECT_FALSE(did_receive);

  source.Resume();

  WaitForSemaphore(signal);
  dispatch_release(signal);
}

}  // namespace base::apple