Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions backends/apple/coreai/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ endif()

enable_language(OBJCXX)

set(_coreai_runtime_sources runtime/coreai_assets.mm)
set(_coreai_runtime_sources runtime/coreai_assets.mm runtime/coreai_storage.mm)

function(coreai_configure_objc_target target)
target_include_directories(
Expand All @@ -32,7 +32,8 @@ if(EXECUTORCH_BUILD_TESTS)
add_executable(
coreai_host_test
runtime/test/coreai_host_test.mm runtime/test/coreai_manifest_test.mm
${_coreai_runtime_sources}
runtime/test/coreai_storage_test.mm
runtime/test/coreai_filesystem_fixture.mm ${_coreai_runtime_sources}
)
coreai_configure_objc_target(coreai_host_test)
target_compile_definitions(coreai_host_test PRIVATE COREAI_ASSETS_TESTING=1)
Expand Down
13 changes: 13 additions & 0 deletions backends/apple/coreai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ architectures=["h17p"])` requests that compiler architecture; omitting the list
lets the compiler emit its supported architectures for the target platform.
These are Core AI architecture names, not CPU names such as `arm64`.

### Asset storage

The assets root must be an absolute path. The application chooses it, should
reserve it for this backend, and is trusted not to rename, replace or modify its
contents while the backend uses it; the backend does not defend against other
processes of the same user rebinding paths. Written files and changed directories
are synced with `fsync`; atomic publication also uses `F_FULLFSYNC` before its
rename.

Preparing the assets root sets `NSURLIsExcludedFromBackupKey` on it, which covers
everything beneath it. Ancestors are not modified. This is backup exclusion, not
a control for iCloud Drive synchronization.

## Host Tests

`EXECUTORCH_BUILD_COREAI=ON` with `EXECUTORCH_BUILD_TESTS=ON` registers the
Expand Down
53 changes: 53 additions & 0 deletions backends/apple/coreai/runtime/coreai_file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <unistd.h>
#include <cerrno>

namespace executorch::backends::coreai {

class FileDescriptor {
public:
explicit FileDescriptor(int fd) : fd_(fd) {}
~FileDescriptor() {
reset(-1);
}
FileDescriptor(const FileDescriptor&) = delete;
FileDescriptor& operator=(const FileDescriptor&) = delete;
int get() const {
return fd_;
}
int release() {
const int fd = fd_;
fd_ = -1;
return fd;
}
void reset(int fd) {
if (fd_ >= 0) {
// Retrying close can close a descriptor reused by another thread.
::close(fd_);
}
fd_ = fd;
}

private:
int fd_;
};

template <typename F>
auto retry_eintr(F call) {
decltype(call()) result;
do {
result = call();
} while (result == -1 && errno == EINTR);
return result;
}

} // namespace executorch::backends::coreai
60 changes: 60 additions & 0 deletions backends/apple/coreai/runtime/coreai_storage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#import <Foundation/Foundation.h>
#include <executorch/runtime/core/result.h>
#include <cstddef>

namespace executorch::backends::coreai {

// Resolves the default location without creating or modifying storage.
runtime::Result<NSString*> default_coreai_assets_root();
// Requires an absolute directory path. With create, makes the directory and
// excludes it from backup; otherwise a missing directory is InvalidArgument.
runtime::Result<NSString*> prepare_storage_root(NSString* path, bool create);
runtime::Error ensure_excluded_from_backup(NSURL* directory);

runtime::Error sync_storage_directory(int fd);
// Returns an independently owned descriptor for a stable coordination file.
int open_storage_shared_file(int parent_fd, const char* name);
// Creates a new file and missing parents, then syncs the file and its parent.
runtime::Error write_storage_file(
int root_fd,
NSString* relative_path,
const void* bytes,
size_t size);
// Atomically replaces name with data. On error, readers see either the old or
// the new complete bytes.
runtime::Error publish_storage_data(int root_fd, NSString* name, NSData* data);
runtime::Result<NSArray<NSString*>*> storage_children(
int fd,
bool skip_invalid_names = false);

enum class StorageOperation {
Rename,
BeforeSDK,
AfterSDK,
BeforeEvict,
AfterEvict,
Remove,
};
#if defined(COREAI_ASSETS_TESTING) && COREAI_ASSETS_TESTING
int storage_fault(StorageOperation operation);
namespace testing {
using StorageFaultCallback = int (*)(StorageOperation);
extern thread_local StorageFaultCallback storage_fault_callback;
} // namespace testing
#else
constexpr int storage_fault(StorageOperation) {
return 0;
}
#endif

} // namespace executorch::backends::coreai
Loading
Loading