2019-11-04 00:01:55 +03:00
|
|
|
/*
|
2021-12-30 05:49:39 +03:00
|
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
2019-06-12 11:32:13 +03:00
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
|
|
|
#import <FBControlCore/FBProcessStream.h>
|
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
/**
|
2021-06-15 11:14:32 +03:00
|
|
|
A result of "attaching" to an IO object, realized as file descriptors.
|
2019-06-12 11:32:13 +03:00
|
|
|
*/
|
|
|
|
@interface FBProcessIOAttachment : NSObject
|
|
|
|
|
|
|
|
#pragma mark Properties
|
|
|
|
|
|
|
|
/**
|
|
|
|
The attachment for stdin.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessStreamAttachment *stdIn;
|
|
|
|
|
|
|
|
/**
|
|
|
|
The attachment for stdout.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessStreamAttachment *stdOut;
|
|
|
|
|
|
|
|
/**
|
|
|
|
The attachment for stderr.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessStreamAttachment *stdErr;
|
|
|
|
|
2021-06-28 15:37:00 +03:00
|
|
|
/**
|
|
|
|
Detach from all the streams.
|
|
|
|
This may be called multiple times, the underlying streams will only detach once per instance.
|
|
|
|
*/
|
|
|
|
- (FBFuture<NSNull *> *)detach;
|
|
|
|
|
2019-06-12 11:32:13 +03:00
|
|
|
@end
|
|
|
|
|
2021-06-15 11:14:32 +03:00
|
|
|
/**
|
|
|
|
A result of "attaching" to an IO object, realized as file paths.
|
|
|
|
*/
|
|
|
|
@interface FBProcessFileAttachment : NSObject
|
|
|
|
|
|
|
|
/**
|
|
|
|
The attachment for stdout.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, nullable, readonly) id<FBProcessFileOutput> stdOut;
|
|
|
|
|
|
|
|
/**
|
|
|
|
The attachment for stderr.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, nullable, readonly) id<FBProcessFileOutput> stdErr;
|
|
|
|
|
2021-06-28 15:37:00 +03:00
|
|
|
/**
|
|
|
|
Detach from all the streams.
|
|
|
|
This may be called multiple times, the underlying streams will only detach once per instance.
|
|
|
|
*/
|
|
|
|
- (FBFuture<NSNull *> *)detach;
|
|
|
|
|
2021-06-15 11:14:32 +03:00
|
|
|
@end
|
|
|
|
|
2019-06-12 11:32:13 +03:00
|
|
|
/**
|
2021-06-28 15:37:00 +03:00
|
|
|
A composite of streams for the stdin, stdout and stderr streams connected to a process.
|
2019-06-12 11:32:13 +03:00
|
|
|
*/
|
2021-08-16 10:37:07 +03:00
|
|
|
@interface FBProcessIO <StdInType : id, StdOutType : id, StdErrType : id> : NSObject
|
2019-06-12 11:32:13 +03:00
|
|
|
|
|
|
|
#pragma mark Initializers
|
|
|
|
|
|
|
|
/**
|
|
|
|
The Designated Initializer.
|
|
|
|
|
|
|
|
@param stdIn the stdin.
|
|
|
|
@param stdOut the stdout.
|
|
|
|
@param stdErr the stderr.
|
|
|
|
@return a new FBProcessIO instance.
|
|
|
|
*/
|
2021-08-16 10:37:07 +03:00
|
|
|
- (instancetype)initWithStdIn:(nullable FBProcessInput<StdInType> *)stdIn stdOut:(nullable FBProcessOutput<StdOutType> *)stdOut stdErr:(nullable FBProcessOutput<StdErrType> *)stdErr;
|
2019-06-12 11:32:13 +03:00
|
|
|
|
2021-06-15 11:14:32 +03:00
|
|
|
/**
|
|
|
|
An IO object that accepts no input and returns no output.
|
|
|
|
*/
|
|
|
|
+ (instancetype)outputToDevNull;
|
|
|
|
|
2019-06-12 11:32:13 +03:00
|
|
|
#pragma mark Properties
|
|
|
|
|
|
|
|
/**
|
|
|
|
The FBProcessInput for stdin.
|
|
|
|
*/
|
2021-08-16 10:37:07 +03:00
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessInput<StdInType> *stdIn;
|
2019-06-12 11:32:13 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
The FBProcessOutput for stdout.
|
|
|
|
*/
|
2021-08-16 10:37:07 +03:00
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessOutput<StdOutType> *stdOut;
|
2019-06-12 11:32:13 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
The FBProcessOutput for stderr.
|
|
|
|
*/
|
2021-08-16 10:37:07 +03:00
|
|
|
@property (nonatomic, strong, nullable, readonly) FBProcessOutput<StdErrType> *stdErr;
|
2019-06-12 11:32:13 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
The queue to use.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, strong, readonly) dispatch_queue_t queue;
|
|
|
|
|
|
|
|
#pragma mark Methods
|
|
|
|
|
|
|
|
/**
|
2021-06-15 11:14:32 +03:00
|
|
|
Attach to all the streams, returning the composite attachment for file descriptors.
|
2019-06-12 11:32:13 +03:00
|
|
|
Will error if any of the stream attachments error.
|
|
|
|
If any of the stream attachments error, then any succeeding attachments will detach.
|
FBProcessIO: Attachment only once, detachment allowed multiple times
Summary:
`-[FBProcessIO detach]` should be called at least one time once a process has exited. However, the current implementation for pipe-based consumers (data consumers, block consumers etc) if `-[FBProcessIO detach]` will error out and bail early another detachment is occurring. That started detachment may finish after the error condition, if the caller is listening for the errored-out attachment, then detachment errors can occur before the detachment has finished elsewhere
This identifies another race condition; D29194120 (https://github.com/facebook/idb/commit/dac5809e4198cc576568a2c6fd0ed94f2732fbd8) fixes problems in `FBTask` where the properties on it do not wait until IO is drained. However, there's still a problem that relates to `-[FBProcessIO detach]`.
1) A process is running, with the process futures all wrapped with detachment handling.
2) The `-[FBProcessIO detach]` is in sequence for `statLoc`, `exitCode` and `signal`. This causes each output to teardown.
3) The same detachment code is called for each of stdIn, stdErr, stdOut.
4) The teardown for `statLoc`'s `stdOut` teardown can succeed first
5) The teardown for `exitCode`'s `stdOut` teardown then fails and the error is handled
6) However, the real teardown in #4 is still pending. This means that `exitCode` can have resolved, before the teardown has actually occurred, which we explicitly wanted to avoid
There was a further problem with the `FBProcessIO` class. Since the internal queue used for serialisation was a concurrent queue, all of the serialisation that was necessary to prevent attachments and detachments from fighting with each other was effectively redundant. This could have resulted in crashes and other indeterminate states if attachments and detachments ran concurrently with themselves or each other.
Reviewed By: jbardini
Differential Revision: D29195990
fbshipit-source-id: 50722ce1eb4293ac6cf6183459d169b42e0c40e7
2021-06-17 18:13:15 +03:00
|
|
|
This should only be called once. Calling attach more than once per instance will fail.
|
2019-06-12 11:32:13 +03:00
|
|
|
*/
|
|
|
|
- (FBFuture<FBProcessIOAttachment *> *)attach;
|
|
|
|
|
2021-06-15 11:14:32 +03:00
|
|
|
/**
|
|
|
|
Attach to all the streams, returning the composite attachment for file paths.
|
|
|
|
Will error if any of the stream attachments error.
|
|
|
|
If any of the stream attachments error, then any succeeding attachments will detach.
|
|
|
|
*/
|
|
|
|
- (FBFuture<FBProcessFileAttachment *> *)attachViaFile;
|
|
|
|
|
2019-06-12 11:32:13 +03:00
|
|
|
@end
|
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_END
|