Skip to content

Commit

Permalink
Implement CFAllocator
Browse filesBrowse the repository at this point in the history
@mszoek
mszoek committedOct 2, 2024
1 parent 310dff8 commit a490a70
Showing 2 changed files with 254 additions and 170 deletions.
395 changes: 227 additions & 168 deletions Frameworks/CoreFoundation/CFBase.m
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,252 @@
/*
* CFAllocator classes
* Copyright (C) 2024 Zoe Knox <zoe@ravynsoft.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


#import <CoreFoundation/CFBase.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSRaise.h>
#import <Foundation/NSCFTypeID.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSFileManager.h>
#ifdef WINDOWS
#include <windows.h>
#endif
#import <Foundation/NSPlatform.h>
#import <pthread.h>

static struct CFAllocator {
uintptr_t cfisa;
CFIndex version;
void *info;
void *retain;
void *release;
void *copyDescription;
void *allocate;
void *reallocate;
void *deallocate;
void *preferredSize;
};

@interface __CFAllocator : NSObject {
CFAllocatorContext _context;
}

-initWithContext:(CFAllocatorContext *)ctx;
-(CFAllocatorContext *)getContext;
@end

@implementation __CFAllocator
-initWithContext:(CFAllocatorContext *)ctx {
self = [super new];
memmove(&_context, ctx, sizeof(CFAllocatorContext));
return self;
}

-(CFAllocatorContext *)getContext {
return &_context;
}
@end

static void *__CFAllocatorMallocAllocate(CFIndex size, CFOptionFlags hint, void *info) {
return malloc(size);
}

static CFStringRef __CFAllocatorMallocCopyDescription(const void *info) {
return (__bridge_retained CFStringRef)[NSString stringWithString:@"CFAllocatorMalloc"];
}

static void __CFAllocatorMallocDeallocate(void *ptr, void *info) {
free(ptr);
}

static void *__CFAllocatorMallocReallocate(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
return realloc(ptr, size);
}

static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
return NULL;
}

static CFStringRef __CFAllocatorNullCopyDescription(const void *info) {
return (__bridge_retained CFStringRef)[NSString stringWithString:@"CFAllocatorNull"];
}

const CFAllocatorRef kCFAllocatorDefault;
const CFAllocatorRef kCFAllocatorSystemDefault;
const CFAllocatorRef kCFAllocatorMalloc;
const CFAllocatorRef kCFAllocatorMallocZone;
const CFAllocatorRef kCFAllocatorNull;
static void __CFAllocatorNullDeallocate(void *ptr, void *info) {
return;
}

static void *__CFAllocatorNullReallocate(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
return NULL;
}

static CFIndex __CFAllocatorNullPreferredSize(CFIndex size, CFOptionFlags hint, void *info) {
return 0;
}

static struct CFAllocator __CFAllocatorMalloc = {
.cfisa = 0,
.version = 0,
.info = NULL,
.retain = NULL,
.release = NULL,
.copyDescription = __CFAllocatorMallocCopyDescription,
.allocate = __CFAllocatorMallocAllocate,
.reallocate = __CFAllocatorMallocReallocate,
.deallocate = __CFAllocatorMallocDeallocate,
.preferredSize = NULL,
};

static struct CFAllocator __CFAllocatorNull = {
.cfisa = 0,
.version = 0,
.info = NULL,
.retain = NULL,
.release = NULL,
.copyDescription = __CFAllocatorNullCopyDescription,
.allocate = __CFAllocatorNullAllocate,
.reallocate = __CFAllocatorNullReallocate,
.deallocate = __CFAllocatorNullDeallocate,
.preferredSize = __CFAllocatorNullPreferredSize,
};

const CFAllocatorRef kCFAllocatorDefault = NULL;
const CFAllocatorRef kCFAllocatorSystemDefault = &__CFAllocatorMalloc;
const CFAllocatorRef kCFAllocatorMalloc = &__CFAllocatorMalloc;
const CFAllocatorRef kCFAllocatorMallocZone = &__CFAllocatorMalloc;
const CFAllocatorRef kCFAllocatorNull = &__CFAllocatorNull;
const CFAllocatorRef kCFAllocatorUseContext;

CFAllocatorRef CFAllocatorGetDefault(void){
NSUnimplementedFunction();
return 0;
static pthread_key_t __kCFAllocatorDefaultKey;
static Boolean __kCFAllocatorDefaultKeyValid = FALSE;

CFAllocatorRef CFAllocatorGetDefault(void) {
// First, make sure our predefined allocators are valid. We do it here
// because this function is called in almost every path.
__CFAllocatorMalloc.cfisa = (uintptr_t)[__CFAllocator class];
__CFAllocatorNull.cfisa = (uintptr_t)[__CFAllocator class];

// check for valid TSD key
if(!__kCFAllocatorDefaultKeyValid) {
if(pthread_key_create(&__kCFAllocatorDefaultKey, NULL) == 0) {
__kCFAllocatorDefaultKeyValid = TRUE;
}
// we know there's no value set if we had to create the key
return kCFAllocatorSystemDefault;
}

void *val = pthread_getspecific(__kCFAllocatorDefaultKey);
if(val != NULL)
return val;
return kCFAllocatorSystemDefault;
}

void CFAllocatorSetDefault(CFAllocatorRef self){
void CFAllocatorSetDefault(CFAllocatorRef self) {
// check for valid TSD key
if(!__kCFAllocatorDefaultKeyValid)
if(pthread_key_create(&__kCFAllocatorDefaultKey, NULL) != 0)
return;
__kCFAllocatorDefaultKeyValid = TRUE;
pthread_setspecific(__kCFAllocatorDefaultKey, self);
}

CFTypeID CFAllocatorGetTypeID(void){
return kNSCFTypeAllocator;
CFTypeID CFAllocatorGetTypeID(void) {
return kNSCFTypeAllocator;
}

CFAllocatorRef CFAllocatorCreate(CFAllocatorRef self,CFAllocatorContext *context){
NSUnimplementedFunction();
return 0;
CFAllocatorRef CFAllocatorCreate(CFAllocatorRef self, CFAllocatorContext *context) {
CFAllocatorRef newAlloc = NULL;
__CFAllocator *o = [__CFAllocator alloc];
size_t size = class_getInstanceSize([o class]);

if(self == kCFAllocatorUseContext) {
newAlloc = context->allocate(size, 0, NULL);
} else {
CFAllocatorRef alloc = CFAllocatorGetDefault();
newAlloc = CFAllocatorAllocate(alloc, size, 0);
}
memmove(newAlloc, o, size); // fix up the isa pointer
o = nil;
[(__CFAllocator *)newAlloc initWithContext:context];
return newAlloc;
}

void CFAllocatorGetContext(CFAllocatorRef self,CFAllocatorContext *context){
void CFAllocatorGetContext(CFAllocatorRef self, CFAllocatorContext *context) {
if(self == NULL)
self = CFAllocatorGetDefault();
memmove(context, [(__CFAllocator *)self getContext], sizeof(CFAllocatorContext));
}
CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef self,CFIndex size,CFOptionFlags hint){
NSUnimplementedFunction();
return 0;

CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef self, CFIndex size, CFOptionFlags hint) {
if(size <= 0)
return size;
if(self == NULL)
self = CFAllocatorGetDefault();
CFAllocatorPreferredSizeCallBack cb = [(__CFAllocator *)self getContext]->preferredSize;
if(cb == NULL)
return size;
return cb(size, 0, NULL);
}

void *CFAllocatorAllocate(CFAllocatorRef self,CFIndex size,CFOptionFlags hint){
NSUnimplementedFunction();
return 0;
void *CFAllocatorAllocate(CFAllocatorRef self, CFIndex size, CFOptionFlags hint) {
if(size <= 0)
return NULL;
if(self == NULL)
self = CFAllocatorGetDefault();
CFAllocatorAllocateCallBack cb = [(__CFAllocator *)self getContext]->allocate;
if(cb == NULL)
return NULL;
return cb(size, 0, NULL);
}
void CFAllocatorDeallocate(CFAllocatorRef self,void *ptr){
NSUnimplementedFunction();

void CFAllocatorDeallocate(CFAllocatorRef self, void *ptr) {
if(ptr == NULL)
return;
if(self == NULL)
self = CFAllocatorGetDefault();
CFAllocatorDeallocateCallBack cb = [(__CFAllocator *)self getContext]->deallocate;
if(cb == NULL)
return;
cb(ptr, NULL);
}
void *CFAllocatorReallocate(CFAllocatorRef self,void *ptr,CFIndex size,CFOptionFlags hint){
NSUnimplementedFunction();
return 0;

void *CFAllocatorReallocate(CFAllocatorRef self, void *ptr, CFIndex size, CFOptionFlags hint) {
if(self == NULL)
self = CFAllocatorGetDefault();

if(ptr == NULL) {
if(size > 0) { // need to allocate
return CFAllocatorAllocate(self, size, hint);
}
return NULL;
}

// ptr is not null
if(size == 0) { // need to deallocate
CFAllocatorDeallocate(self, ptr);
return NULL; // guessing here... Apple's doc doesn't specify return code
}

CFAllocatorReallocateCallBack cb = [(__CFAllocator *)self getContext]->reallocate;
if(cb == NULL)
return NULL;
return cb(ptr, size, 0, NULL);
}


@@ -95,153 +293,14 @@ CFTypeRef CFMakeCollectable(CFTypeRef self){
}

#ifndef MACH

uint64_t mach_absolute_time(void) {
#ifdef WINDOWS
LARGE_INTEGER value={{0}};

// QueryPerformanceCounter() may jump ahead by seconds on old systems
// http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&

if(!QueryPerformanceCounter(&value))
return 0;

return value.QuadPart;
#else
return 0;
#endif
}

kern_return_t mach_timebase_info(mach_timebase_info_t timebase) {
#ifdef WINDOWS
LARGE_INTEGER value={{0}};

if(QueryPerformanceFrequency(&value)){
timebase->numer=1000000000;
timebase->denom=value.QuadPart;
return KERN_SUCCESS;
}
#endif

timebase->numer=1;
timebase->denom=1;
return KERN_FAILURE;
}

#endif


#ifdef WINDOWS
unsigned int sleep(unsigned int seconds) {
Sleep(seconds*1000);
return 0;
}

int usleep(long useconds) {
Sleep(useconds/1000);
return 0;
}

size_t strlcpy(char *dst, const char *src, size_t size) {
int i,count=size;

for(i=0;i<count-1;i++)
dst[i]=src[i];

dst[i]='\0';

return i;
}

char *strnstr(const char *s1,const char *s2, size_t n) {
if(s2[0]=='\0')
return (char *)s1;

size_t i,patLength=strlen(s2);

for(i=0;s1[i]!='\0' && i+patLength<=n;i++)
if(strncmp(s1+i,s2,patLength)==0)
return (char *)(s1+i);

return NULL;
}

void bzero(void *ptr,size_t size){
size_t i;

for(i=0;i<size;i++)
((unsigned char *)ptr)[i]=0;
}

void bcopy(const void *s1, void *s2, size_t n) {
size_t i;

for(i=0;i<n;i++)
((unsigned char *)s2)[i]=((unsigned char *)s1)[i];
}

int bcmp(const void *s1, void *s2, size_t n) {
size_t i;

for(i=0;i<n;i++)
if(((unsigned char *)s2)[i]!=((unsigned char *)s1)[i])
return 1;

return 0;
}

int mkstemps(char *template,int suffixlen) {
HANDLE result=NULL;
const char *table="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
int modulo=strlen(table);
int counter=GetTickCount();
NSString *check;
int length=strlen(template),pos=length-suffixlen;

while(--pos>=0){
if(template[pos]!='X'){
pos++;
break;
}
}

int i,failSafe=0;
char try[length+1];

do {

for(i=0;i<length;i++)
if(i<pos || i>=length-suffixlen)
try[i]=template[i];
else {
try[i]=table[counter%modulo];
counter+=i;
}

try[i]=0;

check=[NSString stringWithUTF8String:try];

NSLog(@"mkstemps try=%@",check);

result=CreateFileW([check fileSystemRepresentationW],GENERIC_WRITE|GENERIC_READ,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);

failSafe++;

}while(result==NULL && failSafe<100);

if(result!=NULL){
for(i=0;i<length;i++)
template[i]=try[i];
template[i]=0;
}

return (int)result;
}

long random(void) {
// rand() is only good for 15 bits, random() returns 31
return (rand()<<16)|(rand()<<1)|(rand()&0x1);
}

#endif
29 changes: 27 additions & 2 deletions Frameworks/CoreFoundation/CFMachPort.m
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
Boolean isValid;
};

void *_CFMachPortReceive(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);
Boolean _CFMachPortIsEqual(const void *info1, const void *info2);

COREFOUNDATION_EXPORT CFTypeID CFMachPortGetTypeID(void) {
return kNSCFTypeMachPort;
}
@@ -115,8 +118,19 @@ COREFOUNDATION_EXPORT void CFMachPortSetInvalidationCallBack(CFMachPortRef self,
}

COREFOUNDATION_EXPORT CFRunLoopSourceRef
CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMachPortRef self, CFIndex order) {
return NULL; // FIXME: implement
CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMachPortRef self, CFIndex order) {
CFRunLoopSourceContext1 rlctx = {
.version = 1,
.info = self,
.retain = CFRetain,
.release = CFRelease,
.copyDescription = NULL,
.equal = _CFMachPortIsEqual,
.hash = NULL,
.getPort = (CFRunLoopGetPortCallBack)CFMachPortGetPort,
.perform = _CFMachPortReceive,
};
return CFRunLoopSourceCreate(NULL, 0, &rlctx);
}

COREFOUNDATION_EXPORT void CFMachPortInvalidate(CFMachPortRef self) {
@@ -137,3 +151,14 @@ COREFOUNDATION_EXPORT Boolean CFMachPortIsValid(CFMachPortRef self) {
return self->isValid;
}


// private for CFRunLoop
void *_CFMachPortReceive(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) {
CFMachPortRef self = (CFMachPortRef)info;
(self->callback)(self, msg, size, self->ctx.info);
}

Boolean _CFMachPortIsEqual(const void *info1, const void *info2) {
return (info1 == info2) ? TRUE : FALSE;
}

0 comments on commit a490a70

Please sign in to comment.