mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add NotifyServer and its test.
TEST=util_test NotifyServerTest.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/804633002
This commit is contained in:
parent
4263334db8
commit
d78b003ef1
@ -59,13 +59,10 @@ class ChildPortServer : public MachMessageServer::Interface {
|
||||
explicit ChildPortServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
|
@ -102,13 +102,10 @@ class UniversalMachExcServer final : public MachMessageServer::Interface {
|
||||
~UniversalMachExcServer();
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
|
245
util/mach/notify_server.cc
Normal file
245
util/mach/notify_server.cc
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/mach/notify_server.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "util/mach/notifyServer.h"
|
||||
#include "util/mach/mach_message.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// These five functions are not used, and are in fact obsoleted by the other
|
||||
// functionality implemented in this file. The standard MIG-generated
|
||||
// notify_server() (in notifyServer.c) server dispatch routine usable with the
|
||||
// standard mach_msg_server() function calls out to this function.
|
||||
// notify_server() is unused and is replaced by the more flexible NotifyServer,
|
||||
// but the linker still needs to see these five function definitions.
|
||||
|
||||
kern_return_t do_mach_notify_port_deleted(notify_port_t notify,
|
||||
mach_port_name_t name) {
|
||||
NOTREACHED();
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
kern_return_t do_mach_notify_port_destroyed(notify_port_t notify,
|
||||
mach_port_t rights) {
|
||||
NOTREACHED();
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
kern_return_t do_mach_notify_no_senders(notify_port_t notify,
|
||||
mach_port_mscount_t mscount) {
|
||||
NOTREACHED();
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
kern_return_t do_mach_notify_send_once(notify_port_t notify) {
|
||||
NOTREACHED();
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
kern_return_t do_mach_notify_dead_name(notify_port_t notify,
|
||||
mach_port_name_t name) {
|
||||
NOTREACHED();
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
namespace {
|
||||
|
||||
// The MIG-generated __MIG_check__Request__*() functions are not declared as
|
||||
// accepting const data, but they could have been because they in fact do not
|
||||
// modify the data. These wrapper functions are provided to bridge the const gap
|
||||
// between the code in this file, which is const-correct and treats request
|
||||
// message data as const, and the generated functions.
|
||||
|
||||
kern_return_t MIGCheckRequestMachNotifyPortDeleted(
|
||||
const __Request__mach_notify_port_deleted_t* in_request) {
|
||||
using Request = __Request__mach_notify_port_deleted_t;
|
||||
return __MIG_check__Request__mach_notify_port_deleted_t(
|
||||
const_cast<Request*>(in_request));
|
||||
}
|
||||
|
||||
kern_return_t MIGCheckRequestMachNotifyPortDestroyed(
|
||||
const __Request__mach_notify_port_destroyed_t* in_request) {
|
||||
using Request = __Request__mach_notify_port_destroyed_t;
|
||||
return __MIG_check__Request__mach_notify_port_destroyed_t(
|
||||
const_cast<Request*>(in_request));
|
||||
}
|
||||
|
||||
kern_return_t MIGCheckRequestMachNotifyNoSenders(
|
||||
const __Request__mach_notify_no_senders_t* in_request) {
|
||||
using Request = __Request__mach_notify_no_senders_t;
|
||||
return __MIG_check__Request__mach_notify_no_senders_t(
|
||||
const_cast<Request*>(in_request));
|
||||
}
|
||||
|
||||
kern_return_t MIGCheckRequestMachNotifySendOnce(
|
||||
const __Request__mach_notify_send_once_t* in_request) {
|
||||
using Request = __Request__mach_notify_send_once_t;
|
||||
return __MIG_check__Request__mach_notify_send_once_t(
|
||||
const_cast<Request*>(in_request));
|
||||
}
|
||||
|
||||
kern_return_t MIGCheckRequestMachNotifyDeadName(
|
||||
const __Request__mach_notify_dead_name_t* in_request) {
|
||||
using Request = __Request__mach_notify_dead_name_t;
|
||||
return __MIG_check__Request__mach_notify_dead_name_t(
|
||||
const_cast<Request*>(in_request));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
NotifyServer::NotifyServer(NotifyServer::Interface* interface)
|
||||
: MachMessageServer::Interface(),
|
||||
interface_(interface) {
|
||||
}
|
||||
|
||||
bool NotifyServer::MachMessageServerFunction(
|
||||
const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||
|
||||
const mach_msg_trailer_t* in_trailer =
|
||||
MachMessageTrailerFromHeader(in_header);
|
||||
|
||||
switch (in_header->msgh_id) {
|
||||
case MACH_NOTIFY_PORT_DELETED: {
|
||||
// mach_notify_port_deleted(), do_mach_notify_port_deleted().
|
||||
using Request = __Request__mach_notify_port_deleted_t;
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachNotifyPortDeleted(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Reply = __Reply__mach_notify_port_deleted_t;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->DoMachNotifyPortDeleted(in_header->msgh_local_port,
|
||||
in_request->name,
|
||||
in_trailer);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MACH_NOTIFY_PORT_DESTROYED: {
|
||||
// mach_notify_port_destroyed(), do_mach_notify_port_destroyed().
|
||||
using Request = __Request__mach_notify_port_destroyed_t;
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachNotifyPortDestroyed(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Reply = __Reply__mach_notify_port_destroyed_t;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->DoMachNotifyPortDestroyed(in_header->msgh_local_port,
|
||||
in_request->rights.name,
|
||||
in_trailer,
|
||||
destroy_complex_request);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MACH_NOTIFY_NO_SENDERS: {
|
||||
// mach_notify_no_senders(), do_mach_notify_no_senders().
|
||||
using Request = __Request__mach_notify_no_senders_t;
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachNotifyNoSenders(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Reply = __Reply__mach_notify_no_senders_t;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->DoMachNotifyNoSenders(in_header->msgh_local_port,
|
||||
in_request->mscount,
|
||||
in_trailer);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MACH_NOTIFY_SEND_ONCE: {
|
||||
// mach_notify_send_once(), do_mach_notify_send_once().
|
||||
using Request = __Request__mach_notify_send_once_t;
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachNotifySendOnce(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Reply = __Reply__mach_notify_send_once_t;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->DoMachNotifySendOnce(in_header->msgh_local_port,
|
||||
in_trailer);
|
||||
return true;
|
||||
}
|
||||
|
||||
case MACH_NOTIFY_DEAD_NAME: {
|
||||
// mach_notify_dead_name(), do_mach_notify_dead_name().
|
||||
using Request = __Request__mach_notify_dead_name_t;
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachNotifyDeadName(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
using Reply = __Reply__mach_notify_dead_name_t;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->DoMachNotifyDeadName(in_header->msgh_local_port,
|
||||
in_request->name,
|
||||
in_trailer);
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<mach_msg_id_t> NotifyServer::MachMessageServerRequestIDs() {
|
||||
const mach_msg_id_t request_ids[] = {
|
||||
MACH_NOTIFY_PORT_DELETED,
|
||||
MACH_NOTIFY_PORT_DESTROYED,
|
||||
MACH_NOTIFY_NO_SENDERS,
|
||||
MACH_NOTIFY_SEND_ONCE,
|
||||
MACH_NOTIFY_DEAD_NAME,
|
||||
};
|
||||
return std::set<mach_msg_id_t>(&request_ids[0],
|
||||
&request_ids[arraysize(request_ids)]);
|
||||
}
|
||||
|
||||
mach_msg_size_t NotifyServer::MachMessageServerRequestSize() {
|
||||
return sizeof(__RequestUnion__do_notify_subsystem);
|
||||
}
|
||||
|
||||
mach_msg_size_t NotifyServer::MachMessageServerReplySize() {
|
||||
return sizeof(__ReplyUnion__do_notify_subsystem);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
193
util/mach/notify_server.h
Normal file
193
util/mach/notify_server.h
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|
||||
#define CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "util/mach/mach_message_server.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief A server interface for the `notify` Mach subsystem.
|
||||
//!
|
||||
//! The <a
|
||||
//! href="https://lists.apple.com/archives/darwin-development/2001/Sep/msg00451.html">mach
|
||||
//! port notifications</a> thread on the <a
|
||||
//! href="https://lists.apple.com/archives/darwin-development/">darwin-development</a>
|
||||
//! mailing list (now known as <a
|
||||
//! href="https://lists.apple.com/mailman/listinfo/darwin-dev">darwin-dev</a>)
|
||||
//! is good background for the various notification types.
|
||||
class NotifyServer : public MachMessageServer::Interface {
|
||||
public:
|
||||
//! \brief An interface that the different request messages that are a part of
|
||||
//! the `notify` Mach subsystem can be dispatched to.
|
||||
class Interface {
|
||||
public:
|
||||
//! \brief Handles port-deleted notifications sent by
|
||||
//! `mach_notify_port_deleted()`.
|
||||
//!
|
||||
//! A port-deleted notification is generated when a port with a dead-name
|
||||
//! notification request is destroyed and the port name becomes available
|
||||
//! for reuse.
|
||||
//!
|
||||
//! This behaves equivalently to a `do_mach_notify_port_deleted()` function
|
||||
//! used with `notify_server()`.
|
||||
//!
|
||||
//! \param[in] notify The Mach port that the notification was sent to.
|
||||
//! \param[in] name The name that formerly referenced the deleted port. When
|
||||
//! this method is called, \a name no longer corresponds to the port
|
||||
//! that has been deleted, and may be reused for another purpose.
|
||||
//! \param[in] trailer The trailer received with the notification message.
|
||||
virtual kern_return_t DoMachNotifyPortDeleted(
|
||||
notify_port_t notify,
|
||||
mach_port_name_t name,
|
||||
const mach_msg_trailer_t* trailer) = 0;
|
||||
|
||||
//! \brief Handles port-destroyed notifications sent by
|
||||
//! `mach_notify_port_destroyed()`.
|
||||
//!
|
||||
//! A port-destroyed notification is generated when a receive right with a
|
||||
//! port-destroyed notification request is destroyed. Rather than destroying
|
||||
//! the receive right, it is transferred via this notification’s \a rights
|
||||
//! parameter.
|
||||
//!
|
||||
//! This behaves equivalently to a `do_mach_notify_port_destroyed()`
|
||||
//! function used with `notify_server()`.
|
||||
//!
|
||||
//! \param[in] notify The Mach port that the notification was sent to.
|
||||
//! \param[in] rights A receive right for the port that would have been
|
||||
//! destroyed. The callee takes ownership of this port, however, if the
|
||||
//! callee does not wish to take ownership, it may set \a
|
||||
//! destroy_request to `true`.
|
||||
//! \param[in] trailer The trailer received with the notification message.
|
||||
//! \param[out] destroy_request `true` if the request message is to be
|
||||
//! destroyed even when this method returns success. See
|
||||
//! MachMessageServer::Interface.
|
||||
virtual kern_return_t DoMachNotifyPortDestroyed(
|
||||
notify_port_t notify,
|
||||
mach_port_t rights,
|
||||
const mach_msg_trailer_t* trailer,
|
||||
bool* destroy_request) = 0;
|
||||
|
||||
//! \brief Handles no-senders notifications sent by
|
||||
//! `mach_notify_no_senders()`.
|
||||
//!
|
||||
//! A no-senders notification is generated when a receive right with a
|
||||
//! no-senders notification request loses its last corresponding send right.
|
||||
//!
|
||||
//! This behaves equivalently to a `do_mach_notify_no_senders()` function
|
||||
//! used with `notify_server()`.
|
||||
//!
|
||||
//! \param[in] notify The Mach port that the notification was sent to.
|
||||
//! \param[in] mscount The value of the sender-less port’s make-send count
|
||||
//! at the time the notification was generated.
|
||||
//! \param[in] trailer The trailer received with the notification message.
|
||||
virtual kern_return_t DoMachNotifyNoSenders(
|
||||
notify_port_t notify,
|
||||
mach_port_mscount_t mscount,
|
||||
const mach_msg_trailer_t* trailer) = 0;
|
||||
|
||||
//! \brief Handles send-once notifications sent by
|
||||
//! `mach_notify_send_once()`.
|
||||
//!
|
||||
//! A send-once notification is generated when a send-once right is
|
||||
//! destroyed without being used.
|
||||
//!
|
||||
//! This behaves equivalently to a `do_mach_notify_send_once()` function
|
||||
//! used with `notify_server()`.
|
||||
//!
|
||||
//! \param[in] notify The Mach port that the notification was sent to.
|
||||
//! \param[in] trailer The trailer received with the notification message.
|
||||
//!
|
||||
//! \note Unlike the other notifications in the `notify` subsystem,
|
||||
//! send-once notifications are not generated as a result of a
|
||||
//! notification request, but are generated any time a send-once right
|
||||
//! is destroyed rather than being used. The notification is sent via
|
||||
//! the send-once right to its receiver. These notifications are more
|
||||
//! useful for clients, not servers. Send-once notifications are
|
||||
//! normally handled by MIG-generated client routines, which make
|
||||
//! send-once rights for their reply ports and interpret send-once
|
||||
//! notifications as a signal that there will be no reply. Although not
|
||||
//! expected to be primarily useful for servers, this method is provided
|
||||
//! because send-once notifications are defined as a part of the
|
||||
//! `notify` subsystem.
|
||||
virtual kern_return_t DoMachNotifySendOnce(
|
||||
notify_port_t notify,
|
||||
const mach_msg_trailer_t* trailer) = 0;
|
||||
|
||||
//! \brief Handles dead-name notifications sent by
|
||||
//! `mach_notify_dead_name()`.
|
||||
//!
|
||||
//! A dead-name notification is generated when a port with a dead-name
|
||||
//! notification request is destroyed and the right becomes a dead name.
|
||||
//!
|
||||
//! This behaves equivalently to a `do_mach_notify_dead_name()` function
|
||||
//! used with `notify_server()`.
|
||||
//!
|
||||
//! \param[in] notify The Mach port that the notification was sent to.
|
||||
//! \param[in] name The dead name. Although this is transferred as a
|
||||
//! `mach_port_name_t` and not a `mach_port_t`, the callee assumes an
|
||||
//! additional reference to this port when this method is called. See
|
||||
//! the note below.
|
||||
//! \param[in] trailer The trailer received with the notification message.
|
||||
//!
|
||||
//! \note When a dead-name notification is generated, the user reference
|
||||
//! count of the dead name is incremented. A send right with one
|
||||
//! reference that becomes a dead name will have one dead-name
|
||||
//! reference, and the dead-name notification will add another dead-name
|
||||
//! reference, for a total of 2. DoMachNotifyDeadName() implementations
|
||||
//! must take care to deallocate this extra reference. There is no \a
|
||||
//! destroy_request parameter to simplify this operation because
|
||||
//! dead-name notifications carry a port name only (\a name is of type
|
||||
//! `mach_port_name_t`) without transferring port rights, and are thus
|
||||
//! not complex Mach messages.
|
||||
virtual kern_return_t DoMachNotifyDeadName(
|
||||
notify_port_t notify,
|
||||
mach_port_name_t name,
|
||||
const mach_msg_trailer_t* trailer) = 0;
|
||||
|
||||
protected:
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
//! \brief Constructs an object of this class.
|
||||
//!
|
||||
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||
explicit NotifyServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
||||
|
||||
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
private:
|
||||
Interface* interface_; // weak
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotifyServer);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|
550
util/mach/notify_server_test.cc
Normal file
550
util/mach/notify_server_test.cc
Normal file
@ -0,0 +1,550 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/mach/notify_server.h"
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/mach/mach_message.h"
|
||||
#include "util/mach/mach_message_server.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using testing::AllOf;
|
||||
using testing::Eq;
|
||||
using testing::Invoke;
|
||||
using testing::Ne;
|
||||
using testing::Pointee;
|
||||
using testing::ResultOf;
|
||||
using testing::Return;
|
||||
using testing::SetArgPointee;
|
||||
using testing::StrictMock;
|
||||
using testing::WithArg;
|
||||
|
||||
//! \brief Allocates and returns a new receive right.
|
||||
//!
|
||||
//! \return The new receive right. On failure, `MACH_PORT_NULL` with a gtest
|
||||
//! failure added.
|
||||
mach_port_t NewReceiveRight() {
|
||||
mach_port_t receive_right;
|
||||
kern_return_t kr = mach_port_allocate(
|
||||
mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &receive_right);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_allocate");
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
return receive_right;
|
||||
}
|
||||
|
||||
//! \brief Adds a send right to an existing receive right.
|
||||
//!
|
||||
//! \param[in] receive_right The receive right to add a send right to.
|
||||
//!
|
||||
//! \return The send right, which will have the same name as the receive right.
|
||||
//! On failure, `MACH_PORT_NULL` with a gtest failure added.
|
||||
mach_port_t SendRightFromReceiveRight(mach_port_t receive_right) {
|
||||
kern_return_t kr = mach_port_insert_right(
|
||||
mach_task_self(), receive_right, receive_right, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr)
|
||||
<< MachErrorMessage(kr, "mach_port_insert_right");
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
return receive_right;
|
||||
}
|
||||
|
||||
//! \brief Extracts a send-once right from a receive right.
|
||||
//!
|
||||
//! \param[in] receive_right The receive right to make a send-once right from.
|
||||
//!
|
||||
//! \return The send-once right. On failure, `MACH_PORT_NULL` with a gtest
|
||||
//! failure added.
|
||||
mach_port_t SendOnceRightFromReceiveRight(mach_port_t receive_right) {
|
||||
mach_port_t send_once_right;
|
||||
mach_msg_type_name_t acquired_type;
|
||||
kern_return_t kr = mach_port_extract_right(mach_task_self(),
|
||||
receive_right,
|
||||
MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
||||
&send_once_right,
|
||||
&acquired_type);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr)
|
||||
<< MachErrorMessage(kr, "mach_port_extract_right");
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
EXPECT_EQ(implicit_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE),
|
||||
acquired_type);
|
||||
|
||||
return send_once_right;
|
||||
}
|
||||
|
||||
//! \brief Deallocates a Mach port by calling `mach_port_deallocate()`.
|
||||
//!
|
||||
//! This function exists to adapt `mach_port_deallocate()` to a function that
|
||||
//! accepts a single argument and has no return value. It can be used with the
|
||||
//! testing::Invoke() gmock action.
|
||||
//!
|
||||
//! On failure, a gtest failure will be added.
|
||||
void MachPortDeallocate(mach_port_t port) {
|
||||
kern_return_t kr = mach_port_deallocate(mach_task_self(), port);
|
||||
EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_deallocate");
|
||||
}
|
||||
|
||||
//! \brief Determines whether a specific right is held for a Mach port.
|
||||
//!
|
||||
//! \param[in] port The port to check for a right.
|
||||
//! \param[in] right The right to check for.
|
||||
//!
|
||||
//! \return `true` if \a port has \a right, `false` otherwise. On faliure,
|
||||
//! `false` with a gtest failure added.
|
||||
bool IsRight(mach_port_t port, mach_port_type_t right) {
|
||||
mach_port_type_t type;
|
||||
kern_return_t kr = mach_port_type(mach_task_self(), port, &type);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_type");
|
||||
return false;
|
||||
}
|
||||
|
||||
return type & right;
|
||||
}
|
||||
|
||||
//! \brief Determines whether a receive right is held for a Mach port.
|
||||
//!
|
||||
//! This is a special single-argument form of IsRight() for ease of use in a
|
||||
//! gmock matcher.
|
||||
//!
|
||||
//! \param[in] port The port to check for a receive right.
|
||||
//!
|
||||
//! \return `true` if a receive right is held, `false` otherwise. On faliure,
|
||||
//! `false` with a gtest failure added.
|
||||
bool IsReceiveRight(mach_port_t port) {
|
||||
return IsRight(port, MACH_PORT_TYPE_RECEIVE);
|
||||
}
|
||||
|
||||
//! \brief Returns the user reference count for port rights.
|
||||
//!
|
||||
//! \param[in] port The port whose user reference count should be returned.
|
||||
//! \param[in] right The port right to return the user reference count for.
|
||||
//!
|
||||
//! \return The user reference count for the specified port and right. On
|
||||
//! failure, `-1` with a gtest failure added.
|
||||
mach_port_urefs_t RightRefCount(mach_port_t port, mach_port_right_t right) {
|
||||
mach_port_urefs_t refs;
|
||||
kern_return_t kr = mach_port_get_refs(mach_task_self(), port, right, &refs);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_get_refs");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
//! \brief Returns the user reference count for a port’s dead-name rights.
|
||||
//!
|
||||
//! This is a special single-argument form of RightRefCount() for ease of use in
|
||||
//! a gmock matcher.
|
||||
//!
|
||||
//! \param[in] port The port whose dead-name user reference count should be
|
||||
//! returned.
|
||||
//!
|
||||
//! \return The user reference count for the port’s dead-name rights. On
|
||||
//! failure, `-1` with a gtest failure added.
|
||||
mach_port_urefs_t DeadNameRightRefCount(mach_port_t port) {
|
||||
return RightRefCount(port, MACH_PORT_RIGHT_DEAD_NAME);
|
||||
}
|
||||
|
||||
class NotifyServerTestBase : public testing::Test,
|
||||
public NotifyServer::Interface {
|
||||
public:
|
||||
// NotifyServer::Interface:
|
||||
|
||||
MOCK_METHOD3(DoMachNotifyPortDeleted,
|
||||
kern_return_t(notify_port_t notify,
|
||||
mach_port_name_t name,
|
||||
const mach_msg_trailer_t* trailer));
|
||||
|
||||
MOCK_METHOD4(DoMachNotifyPortDestroyed,
|
||||
kern_return_t(notify_port_t notify,
|
||||
mach_port_t rights,
|
||||
const mach_msg_trailer_t* trailer,
|
||||
bool* destroy_request));
|
||||
|
||||
MOCK_METHOD3(DoMachNotifyNoSenders,
|
||||
kern_return_t(notify_port_t notify,
|
||||
mach_port_mscount_t mscount,
|
||||
const mach_msg_trailer_t* trailer));
|
||||
|
||||
MOCK_METHOD2(DoMachNotifySendOnce,
|
||||
kern_return_t(notify_port_t notify,
|
||||
const mach_msg_trailer_t* trailer));
|
||||
|
||||
MOCK_METHOD3(DoMachNotifyDeadName,
|
||||
kern_return_t(notify_port_t notify,
|
||||
mach_port_name_t name,
|
||||
const mach_msg_trailer_t* trailer));
|
||||
|
||||
protected:
|
||||
NotifyServerTestBase() : testing::Test(), NotifyServer::Interface() {}
|
||||
|
||||
~NotifyServerTestBase() override {}
|
||||
|
||||
//! \brief Requests a Mach port notification.
|
||||
//!
|
||||
//! \a name, \a variant, and \a sync are passed as-is to
|
||||
//! `mach_port_request_notification()`. The notification will be sent to a
|
||||
//! send-once right made from ServerPort(). Any previous send right for the
|
||||
//! notification will be deallocated.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a gtest failure added.
|
||||
bool RequestMachPortNotification(mach_port_t name,
|
||||
mach_msg_id_t variant,
|
||||
mach_port_mscount_t sync) {
|
||||
mach_port_t previous;
|
||||
kern_return_t kr =
|
||||
mach_port_request_notification(mach_task_self(),
|
||||
name,
|
||||
variant,
|
||||
sync,
|
||||
ServerPort(),
|
||||
MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
||||
&previous);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
EXPECT_EQ(KERN_SUCCESS, kr)
|
||||
<< MachErrorMessage(kr, "mach_port_request_notification");
|
||||
return false;
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight previous_owner(previous);
|
||||
EXPECT_EQ(kMachPortNull, previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! \brief Runs a NotifyServer Mach message server.
|
||||
//!
|
||||
//! The server will listen on ServerPort() in persistent nonblocking mode, and
|
||||
//! dispatch received messages to the appropriate NotifyServer::Interface
|
||||
//! method. gmock expectations check that the proper method, if any, is called
|
||||
//! exactly once, and that no undesired methods are called.
|
||||
//!
|
||||
//! MachMessageServer::Run() is expected to return `MACH_RCV_TIMED_OUT`,
|
||||
//! because it runs in persistent nonblocking mode. If it returns anything
|
||||
//! else, a gtest assertion is added.
|
||||
void RunServer() {
|
||||
NotifyServer notify_server(this);
|
||||
mach_msg_return_t mr =
|
||||
MachMessageServer::Run(¬ify_server,
|
||||
ServerPort(),
|
||||
MACH_MSG_OPTION_NONE,
|
||||
MachMessageServer::kPersistent,
|
||||
MachMessageServer::kReceiveLargeError,
|
||||
kMachMessageTimeoutNonblocking);
|
||||
ASSERT_EQ(MACH_RCV_TIMED_OUT, mr)
|
||||
<< MachErrorMessage(mr, "MachMessageServer::Run");
|
||||
}
|
||||
|
||||
//! \brief Returns the receive right to be used for the server.
|
||||
//!
|
||||
//! This receive right is created lazily on a per-test basis. It is destroyed
|
||||
//! by TearDown() at the conclusion of each test.
|
||||
//!
|
||||
//! \return The server port receive right, creating it if one has not yet been
|
||||
//! established for the current test. On failure, returns `MACH_PORT_NULL`
|
||||
//! with a gtest failure added.
|
||||
mach_port_t ServerPort() {
|
||||
if (!server_port_) {
|
||||
server_port_.reset(NewReceiveRight());
|
||||
}
|
||||
|
||||
return server_port_;
|
||||
}
|
||||
|
||||
// testing::Test:
|
||||
void TearDown() override {
|
||||
server_port_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
base::mac::ScopedMachReceiveRight server_port_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotifyServerTestBase);
|
||||
};
|
||||
|
||||
using NotifyServerTest = StrictMock<NotifyServerTestBase>;
|
||||
|
||||
TEST_F(NotifyServerTest, Basic) {
|
||||
NotifyServer server(this);
|
||||
|
||||
std::set<mach_msg_id_t> expect_request_ids;
|
||||
expect_request_ids.insert(MACH_NOTIFY_PORT_DELETED);
|
||||
expect_request_ids.insert(MACH_NOTIFY_PORT_DESTROYED);
|
||||
expect_request_ids.insert(MACH_NOTIFY_NO_SENDERS);
|
||||
expect_request_ids.insert(MACH_NOTIFY_SEND_ONCE);
|
||||
expect_request_ids.insert(MACH_NOTIFY_DEAD_NAME);
|
||||
EXPECT_EQ(expect_request_ids, server.MachMessageServerRequestIDs());
|
||||
|
||||
// The port-destroyed notification is the largest request message in the
|
||||
// subsystem. <mach/notify.h> defines the same structure, but with a basic
|
||||
// trailer, so use offsetof to get the size of the basic structure without any
|
||||
// trailer.
|
||||
EXPECT_EQ(offsetof(mach_port_destroyed_notification_t, trailer),
|
||||
server.MachMessageServerRequestSize());
|
||||
|
||||
mig_reply_error_t reply;
|
||||
EXPECT_EQ(sizeof(reply), server.MachMessageServerReplySize());
|
||||
}
|
||||
|
||||
// When no notifications are requested, nothing should happen.
|
||||
TEST_F(NotifyServerTest, NoNotification) {
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When a send-once right with a dead-name notification request is deallocated,
|
||||
// a port-deleted notification should be generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyPortDeleted) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
base::mac::ScopedMachSendRight send_once_right(
|
||||
SendOnceRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_once_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
send_once_right, MACH_NOTIFY_DEAD_NAME, 0));
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifyPortDeleted(ServerPort(),
|
||||
send_once_right.get(),
|
||||
Ne(nullptr)))
|
||||
.WillOnce(Return(MIG_NO_REPLY))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
send_once_right.reset();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When a receive right with a port-destroyed notification request is destroyed,
|
||||
// a port-destroyed notification should be generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyPortDestroyed) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
receive_right, MACH_NOTIFY_PORT_DESTROYED, 0));
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifyPortDestroyed(ServerPort(),
|
||||
ResultOf(IsReceiveRight, true),
|
||||
Ne(nullptr),
|
||||
Pointee(Eq(false))))
|
||||
.WillOnce(DoAll(SetArgPointee<3>(true), Return(MIG_NO_REPLY)))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
receive_right.reset();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When a receive right with a port-destroyed notification request is not
|
||||
// destroyed, no port-destroyed notification should be generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyPortDestroyed_NoNotification) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
receive_right, MACH_NOTIFY_PORT_DESTROYED, 0));
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When a no-senders notification request is registered for a receive right with
|
||||
// no senders, a no-senders notification should be generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyNoSenders_NoSendRight) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
receive_right, MACH_NOTIFY_NO_SENDERS, 0));
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifyNoSenders(ServerPort(), 0, Ne(nullptr)))
|
||||
.WillOnce(Return(MIG_NO_REPLY))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When the last send right corresponding to a receive right with a no-senders
|
||||
// notification request is deallocated, a no-senders notification should be
|
||||
// generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyNoSenders_SendRightDeallocated) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
base::mac::ScopedMachSendRight send_right(
|
||||
SendRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
receive_right, MACH_NOTIFY_NO_SENDERS, 1));
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifyNoSenders(ServerPort(), 1, Ne(nullptr)))
|
||||
.WillOnce(Return(MIG_NO_REPLY))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
send_right.reset();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When the a receive right with a no-senders notification request never loses
|
||||
// all senders, no no-senders notification should be generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyNoSenders_NoNotification) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
base::mac::ScopedMachSendRight send_right_0(
|
||||
SendRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_right_0);
|
||||
|
||||
base::mac::ScopedMachSendRight send_right_1(
|
||||
SendRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_right_1);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
receive_right, MACH_NOTIFY_NO_SENDERS, 1));
|
||||
|
||||
send_right_1.reset();
|
||||
|
||||
RunServer();
|
||||
|
||||
EXPECT_EQ(1u, RightRefCount(receive_right, MACH_PORT_RIGHT_RECEIVE));
|
||||
EXPECT_EQ(1u, RightRefCount(receive_right, MACH_PORT_RIGHT_SEND));
|
||||
}
|
||||
|
||||
// When a send-once right is deallocated without being used, a send-once
|
||||
// notification notification should be sent via the send-once right.
|
||||
TEST_F(NotifyServerTest, MachNotifySendOnce_ExplicitDeallocation) {
|
||||
base::mac::ScopedMachSendRight send_once_right(
|
||||
SendOnceRightFromReceiveRight(ServerPort()));
|
||||
ASSERT_NE(kMachPortNull, send_once_right);
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifySendOnce(ServerPort(), Ne(nullptr)))
|
||||
.WillOnce(Return(MIG_NO_REPLY))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
send_once_right.reset();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When a send-once right is sent to a receiver that never dequeues the message,
|
||||
// the send-once right is destroyed, and a send-once notification should appear
|
||||
// on the reply port.
|
||||
TEST_F(NotifyServerTest, MachNotifySendOnce_ImplicitDeallocation) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
mach_msg_empty_send_t message = {};
|
||||
message.header.msgh_bits =
|
||||
MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
|
||||
message.header.msgh_size = sizeof(message);
|
||||
message.header.msgh_remote_port = receive_right;
|
||||
message.header.msgh_local_port = ServerPort();
|
||||
mach_msg_return_t mr = mach_msg(&message.header,
|
||||
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
|
||||
message.header.msgh_size,
|
||||
0,
|
||||
MACH_PORT_NULL,
|
||||
0,
|
||||
MACH_PORT_NULL);
|
||||
ASSERT_EQ(MACH_MSG_SUCCESS, mr) << MachErrorMessage(mr, "mach_msg");
|
||||
|
||||
EXPECT_CALL(*this, DoMachNotifySendOnce(ServerPort(), Ne(nullptr)))
|
||||
.WillOnce(Return(MIG_NO_REPLY))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
receive_right.reset();
|
||||
|
||||
RunServer();
|
||||
}
|
||||
|
||||
// When the receive right corresponding to a send-once right with a dead-name
|
||||
// notification request is destroyed, a dead-name notification should be
|
||||
// generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyDeadName) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
base::mac::ScopedMachSendRight send_once_right(
|
||||
SendOnceRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_once_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
send_once_right, MACH_NOTIFY_DEAD_NAME, 0));
|
||||
|
||||
// send_once_right becomes a dead name with the send-once right’s original
|
||||
// user reference count of 1, but the dead-name notification increments the
|
||||
// dead-name reference count, so it becomes 2. Take care to deallocate that
|
||||
// reference. The original reference is managed by send_once_right_owner.
|
||||
EXPECT_CALL(*this,
|
||||
DoMachNotifyDeadName(ServerPort(),
|
||||
AllOf(send_once_right.get(),
|
||||
ResultOf(DeadNameRightRefCount, 2)),
|
||||
Ne(nullptr)))
|
||||
.WillOnce(DoAll(WithArg<1>(Invoke(MachPortDeallocate)),
|
||||
Return(MIG_NO_REPLY)))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
receive_right.reset();
|
||||
|
||||
RunServer();
|
||||
|
||||
EXPECT_TRUE(IsRight(send_once_right, MACH_PORT_TYPE_DEAD_NAME));
|
||||
|
||||
EXPECT_EQ(0u, RightRefCount(send_once_right, MACH_PORT_RIGHT_SEND_ONCE));
|
||||
EXPECT_EQ(1u, DeadNameRightRefCount(send_once_right));
|
||||
}
|
||||
|
||||
// When the receive right corresponding to a send-once right with a dead-name
|
||||
// notification request is not destroyed, no dead-name notification should be
|
||||
// generated.
|
||||
TEST_F(NotifyServerTest, MachNotifyDeadName_NoNotification) {
|
||||
base::mac::ScopedMachReceiveRight receive_right(NewReceiveRight());
|
||||
ASSERT_NE(kMachPortNull, receive_right);
|
||||
|
||||
base::mac::ScopedMachSendRight send_once_right(
|
||||
SendOnceRightFromReceiveRight(receive_right));
|
||||
ASSERT_NE(kMachPortNull, send_once_right);
|
||||
|
||||
ASSERT_TRUE(RequestMachPortNotification(
|
||||
send_once_right, MACH_NOTIFY_DEAD_NAME, 0));
|
||||
|
||||
RunServer();
|
||||
|
||||
EXPECT_FALSE(IsRight(send_once_right, MACH_PORT_TYPE_DEAD_NAME));
|
||||
|
||||
EXPECT_EQ(1u, RightRefCount(send_once_right, MACH_PORT_RIGHT_SEND_ONCE));
|
||||
EXPECT_EQ(0u, DeadNameRightRefCount(send_once_right));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -62,6 +62,8 @@
|
||||
'mach/mach_message.h',
|
||||
'mach/mach_message_server.cc',
|
||||
'mach/mach_message_server.h',
|
||||
'mach/notify_server.cc',
|
||||
'mach/notify_server.h',
|
||||
'mach/scoped_task_suspend.cc',
|
||||
'mach/scoped_task_suspend.h',
|
||||
'mach/symbolic_constants_mach.cc',
|
||||
@ -126,12 +128,14 @@
|
||||
'files': [
|
||||
'$(SDKROOT)/usr/include/mach/exc.defs',
|
||||
'$(SDKROOT)/usr/include/mach/mach_exc.defs',
|
||||
'$(SDKROOT)/usr/include/mach/notify.defs',
|
||||
],
|
||||
},
|
||||
],
|
||||
'sources': [
|
||||
'<(INTERMEDIATE_DIR)/util/mach/exc.defs',
|
||||
'<(INTERMEDIATE_DIR)/util/mach/mach_exc.defs',
|
||||
'<(INTERMEDIATE_DIR)/util/mach/notify.defs',
|
||||
],
|
||||
}, { # else: GENERATOR!="ninja"
|
||||
# The Xcode generator does copies after rules, so the above trick
|
||||
@ -140,6 +144,7 @@
|
||||
'sources': [
|
||||
'$(SDKROOT)/usr/include/mach/exc.defs',
|
||||
'$(SDKROOT)/usr/include/mach/mach_exc.defs',
|
||||
'$(SDKROOT)/usr/include/mach/notify.defs',
|
||||
],
|
||||
}],
|
||||
],
|
||||
@ -243,6 +248,7 @@
|
||||
'mach/mach_extensions_test.cc',
|
||||
'mach/mach_message_server_test.cc',
|
||||
'mach/mach_message_test.cc',
|
||||
'mach/notify_server_test.cc',
|
||||
'mach/scoped_task_suspend_test.cc',
|
||||
'mach/symbolic_constants_mach_test.cc',
|
||||
'mach/task_memory_test.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user