aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-03-13 03:10:54 +0000
committerJohn McCall <rjmccall@apple.com>2013-03-13 03:10:54 +0000
commit5b07e8077a20b80fee90bd76c43c6150c676e4a8 (patch)
tree6f93262867be60a728d721269a95eacee6c023ae /lib
parent365bc037d67220dae412b45281f04a96140168da (diff)
Tighten up the rules for precise lifetime and document
the requirements on the ARC optimizer. rdar://13407451 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176924 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CGBlocks.cpp6
-rw-r--r--lib/CodeGen/CGDecl.cpp17
-rw-r--r--lib/CodeGen/CGExpr.cpp16
-rw-r--r--lib/CodeGen/CGExprCXX.cpp2
-rw-r--r--lib/CodeGen/CGObjC.cpp19
-rw-r--r--lib/CodeGen/CGObjCMac.cpp2
-rw-r--r--lib/CodeGen/CGValue.h16
-rw-r--r--lib/CodeGen/CodeGenFunction.h8
8 files changed, 59 insertions, 27 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index b9f466117c..c521bf9472 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1547,7 +1547,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// Destroy strong objects with a call if requested.
} else if (useARCStrongDestroy) {
- EmitARCDestroyStrong(srcField, /*precise*/ false);
+ EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
@@ -1656,7 +1656,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1686,7 +1686,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 0e001301ae..f9f48ae9ca 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -627,7 +627,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, ARCImpreciseLifetime);
return;
}
@@ -1490,12 +1490,15 @@ namespace {
/// ns_consumed argument when we can't reasonably do that just by
/// not doing the initial retain for a __block argument.
struct ConsumeARCParameter : EHScopeStack::Cleanup {
- ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+ ConsumeARCParameter(llvm::Value *param,
+ ARCPreciseLifetime_t precise)
+ : Param(param), Precise(precise) {}
llvm::Value *Param;
+ ARCPreciseLifetime_t Precise;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(Param, /*precise*/ false);
+ CGF.EmitARCRelease(Param, Precise);
}
};
}
@@ -1585,8 +1588,12 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
} else {
// Push the cleanup for a consumed parameter.
- if (isConsumed)
- EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+ if (isConsumed) {
+ ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>()
+ ? ARCPreciseLifetime : ARCImpreciseLifetime);
+ EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg,
+ precise);
+ }
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 5e6342ae38..e551343119 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1800,10 +1800,6 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
bool isBlockVariable = VD->hasAttr<BlocksAttr>();
- bool NonGCable = VD->hasLocalStorage() &&
- !VD->getType()->isReferenceType() &&
- !isBlockVariable;
-
llvm::Value *V = LocalDeclMap.lookup(VD);
if (!V && VD->isStaticLocal())
V = CGM.getStaticLocalDeclAddress(VD);
@@ -1837,10 +1833,20 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
LV = MakeAddrLValue(V, T, Alignment);
}
+ bool isLocalStorage = VD->hasLocalStorage();
+
+ bool NonGCable = isLocalStorage &&
+ !VD->getType()->isReferenceType() &&
+ !isBlockVariable;
if (NonGCable) {
LV.getQuals().removeObjCGCAttr();
LV.setNonGC(true);
}
+
+ bool isImpreciseLifetime =
+ (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>());
+ if (isImpreciseLifetime)
+ LV.setARCPreciseLifetime(ARCImpreciseLifetime);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
@@ -2911,7 +2917,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
case Qualifiers::OCL_Strong:
EmitARCRelease(Builder.CreateLoad(BaseValue,
PseudoDtor->getDestroyedType().isVolatileQualified()),
- /*precise*/ true);
+ ARCPreciseLifetime);
break;
case Qualifiers::OCL_Weak:
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 13ae8bb01a..83c8ace98c 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1451,7 +1451,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr,
ElementType.isVolatileQualified());
- CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+ CGF.EmitARCRelease(PtrValue, ARCPreciseLifetime);
break;
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index ad7d62951a..f53f2a97c6 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -1686,7 +1686,8 @@ namespace {
llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(object, /*precise*/ true);
+ // Releases at the end of the full-expression are imprecise.
+ CGF.EmitARCRelease(object, ARCImpreciseLifetime);
}
};
}
@@ -1940,7 +1941,8 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
/// Release the given object.
/// call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+void CodeGenFunction::EmitARCRelease(llvm::Value *value,
+ ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
@@ -1956,7 +1958,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
// Call objc_release.
llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
- if (!precise) {
+ if (precise == ARCImpreciseLifetime) {
SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), args));
@@ -1972,7 +1974,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
/// At -O1 and above, just load and call objc_release.
///
/// call void \@objc_storeStrong(i8** %addr, i8* null)
-void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) {
+void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr,
+ ARCPreciseLifetime_t precise) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
llvm::Value *null = llvm::ConstantPointerNull::get(
@@ -2042,7 +2045,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
EmitStoreOfScalar(newValue, dst);
// Finally, release the old value.
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
return newValue;
}
@@ -2254,13 +2257,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
+ CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2737,7 +2740,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
} else {
value = EmitARCStoreStrong(lvalue, value, ignored);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 975f9ac4af..019c32ea3d 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1617,7 +1617,7 @@ struct NullReturnState {
RValue RV = I->RV;
assert(RV.isScalar() &&
"NullReturnState::complete - arg not on object");
- CGF.EmitARCRelease(RV.getScalarVal(), true);
+ CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
}
}
}
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 6b0c271a08..b7591a76fb 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -97,6 +97,10 @@ public:
}
};
+/// Does an ARC strong l-value have precise lifetime?
+enum ARCPreciseLifetime_t {
+ ARCImpreciseLifetime, ARCPreciseLifetime,
+};
/// LValue - This represents an lvalue references. Because C/C++ allow
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
@@ -147,6 +151,10 @@ class LValue {
// Lvalue is a thread local reference
bool ThreadLocalRef : 1;
+ // Lvalue has ARC imprecise lifetime. We store this inverted to try
+ // to make the default bitfield pattern all-zeroes.
+ bool ImpreciseLifetime : 1;
+
Expr *BaseIvarExp;
/// TBAAInfo - TBAA information to attach to dereferences of this LValue.
@@ -164,6 +172,7 @@ private:
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
+ this->ImpreciseLifetime = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = 0;
this->TBAAInfo = TBAAInfo;
@@ -202,6 +211,13 @@ public:
bool isThreadLocalRef() const { return ThreadLocalRef; }
void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
+ ARCPreciseLifetime_t isARCPreciseLifetime() const {
+ return ARCPreciseLifetime_t(!ImpreciseLifetime);
+ }
+ void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
+ ImpreciseLifetime = (value == ARCImpreciseLifetime);
+ }
+
bool isObjCWeak() const {
return Quals.getObjCGCAttr() == Qualifiers::Weak;
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 0155f033e6..55c21e80ee 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -2446,14 +2446,14 @@ public:
llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
- void EmitARCDestroyStrong(llvm::Value *addr, bool precise);
- void EmitARCRelease(llvm::Value *value, bool precise);
+ void EmitARCDestroyStrong(llvm::Value *addr, ARCPreciseLifetime_t precise);
+ void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
_H */
diff --git a/include/asm-m32r/sockios.h b/include/asm-m32r/sockios.h
index f89962e231f..6c1fb9b43bd 100644
--- a/include/asm-m32r/sockios.h
+++ b/include/asm-m32r/sockios.h
@@ -7,6 +7,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* _ASM_M32R_SOCKIOS_H */
diff --git a/include/asm-m68k/sockios.h b/include/asm-m68k/sockios.h
index 9b9ed973c24..c04a23943cb 100644
--- a/include/asm-m68k/sockios.h
+++ b/include/asm-m68k/sockios.h
@@ -7,6 +7,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* __ARCH_M68K_SOCKIOS__ */
diff --git a/include/asm-mips/sockios.h b/include/asm-mips/sockios.h
index 87a50bf039e..ed1a5f78d22 100644
--- a/include/asm-mips/sockios.h
+++ b/include/asm-mips/sockios.h
@@ -20,6 +20,7 @@
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* _ASM_SOCKIOS_H */
diff --git a/include/asm-parisc/sockios.h b/include/asm-parisc/sockios.h
index aace4962994..dabfbc7483f 100644
--- a/include/asm-parisc/sockios.h
+++ b/include/asm-parisc/sockios.h
@@ -7,6 +7,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif
diff --git a/include/asm-powerpc/sockios.h b/include/asm-powerpc/sockios.h
index 590078d8ed2..55cef7675a3 100644
--- a/include/asm-powerpc/sockios.h
+++ b/include/asm-powerpc/sockios.h
@@ -14,6 +14,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* _ASM_POWERPC_SOCKIOS_H */
diff --git a/include/asm-s390/sockios.h b/include/asm-s390/sockios.h
index 412aeb4dd6c..f4fc16c7da5 100644
--- a/include/asm-s390/sockios.h
+++ b/include/asm-s390/sockios.h
@@ -15,6 +15,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif
diff --git a/include/asm-sh/sockios.h b/include/asm-sh/sockios.h
index 08a71df8a8b..cf8b96b1f9a 100644
--- a/include/asm-sh/sockios.h
+++ b/include/asm-sh/sockios.h
@@ -9,5 +9,6 @@
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS _IOR('s', 101, struct timespec) /* Get stamp (timespec) */
#endif /* __ASM_SH_SOCKIOS_H */
diff --git a/include/asm-sh64/sockios.h b/include/asm-sh64/sockios.h
index 1ae23ae8297..419e76f12f4 100644
--- a/include/asm-sh64/sockios.h
+++ b/include/asm-sh64/sockios.h
@@ -20,5 +20,6 @@
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP _IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS _IOR('s', 101, struct timespec) /* Get stamp (timespec) */
#endif /* __ASM_SH64_SOCKIOS_H */
diff --git a/include/asm-sparc/sockios.h b/include/asm-sparc/sockios.h
index 0c01b597b06..990ea746486 100644
--- a/include/asm-sparc/sockios.h
+++ b/include/asm-sparc/sockios.h
@@ -7,7 +7,8 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* !(_ASM_SPARC_SOCKIOS_H) */
diff --git a/include/asm-sparc64/sockios.h b/include/asm-sparc64/sockios.h
index 6735bab4f39..c7d9900638d 100644
--- a/include/asm-sparc64/sockios.h
+++ b/include/asm-sparc64/sockios.h
@@ -7,7 +7,8 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* !(_ASM_SPARC64_SOCKIOS_H) */
diff --git a/include/asm-v850/sockios.h b/include/asm-v850/sockios.h
index cf4874c2fd8..823e106e6cd 100644
--- a/include/asm-v850/sockios.h
+++ b/include/asm-v850/sockios.h
@@ -7,6 +7,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* __V850_SOCKIOS_H__ */
diff --git a/include/asm-x86_64/sockios.h b/include/asm-x86_64/sockios.h
index 2eefd10d4f4..d726ba2513e 100644
--- a/include/asm-x86_64/sockios.h
+++ b/include/asm-x86_64/sockios.h
@@ -7,6 +7,7 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif
diff --git a/include/asm-xtensa/sockios.h b/include/asm-xtensa/sockios.h
index 20d2ba10ecd..efe0af379f0 100644
--- a/include/asm-xtensa/sockios.h
+++ b/include/asm-xtensa/sockios.h
@@ -25,6 +25,7 @@
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
#endif /* _XTENSA_SOCKIOS_H */
diff --git a/include/net/compat.h b/include/net/compat.h
index 9859b60280d..406db242f73 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -25,6 +25,7 @@ struct compat_cmsghdr {
};
extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
#else /* defined(CONFIG_COMPAT) */
#define compat_msghdr msghdr /* to avoid compiler warnings */
diff --git a/include/net/sock.h b/include/net/sock.h
index 2974bacc885..d093e49fdc8 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1329,6 +1329,7 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e
extern void sock_enable_timestamp(struct sock *sk);
extern int sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int sock_get_timestampns(struct sock *, struct timespec __user *);
/*
* Enable debug/info messages
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index c8b7dc2c325..32b82705b68 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1771,6 +1771,9 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP:
rc = sock_get_timestamp(sk, argp);
break;
+ case SIOCGSTAMPNS:
+ rc = sock_get_timestampns(sk, argp);
+ break;
/* Routing */
case SIOCADDRT:
case SIOCDELRT:
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 8ccee4591f6..7afd8e7754f 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -82,6 +82,9 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP: /* borrowed from IP */
error = sock_get_timestamp(sk, argp);
goto done;
+ case SIOCGSTAMPNS: /* borrowed from IP */
+ error = sock_get_timestampns(sk, argp);
+ goto done;
case ATM_SETSC:
printk(KERN_WARNING "ATM_SETSC is obsolete\n");
error = 0;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 1c07c6a50eb..62605dc5a2c 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1711,6 +1711,10 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
res = sock_get_timestamp(sk, argp);
break;
+ case SIOCGSTAMPNS:
+ res = sock_get_timestampns(sk, argp);
+ break;
+
case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: {
diff --git a/net/compat.c b/net/compat.c
index 17c2710b2b9..2fc6d9bb622 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -564,6 +564,30 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
}
EXPORT_SYMBOL(compat_sock_get_timestamp);
+int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+ struct compat_timespec __user *ctv =
+ (struct compat_timespec __user*) userstamp;
+ int err = -ENOENT;
+ struct timespec ts;
+
+ if (!sock_flag(sk, SOCK_TIMESTAMP))
+ sock_enable_timestamp(sk);
+ ts = ktime_to_timespec(sk->sk_stamp);
+ if (ts.tv_sec == -1)
+ return err;
+ if (ts.tv_sec == 0) {
+ sk->sk_stamp = ktime_get_real();
+ ts = ktime_to_timespec(sk->sk_stamp);
+ }
+ err = 0;
+ if (put_user(ts.tv_sec, &ctv->tv_sec) ||
+ put_user(ts.tv_nsec, &ctv->tv_nsec))
+ err = -EFAULT;
+ return err;
+}
+EXPORT_SYMBOL(compat_sock_get_timestampns);
+
asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char __user *optval, int __user *optlen)
{
diff --git a/net/core/sock.c b/net/core/sock.c
index 6ddb3664b99..cb48fa0e124 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1567,6 +1567,22 @@ int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
}
EXPORT_SYMBOL(sock_get_timestamp);
+int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+ struct timespec ts;
+ if (!sock_flag(sk, SOCK_TIMESTAMP))
+ sock_enable_timestamp(sk);
+ ts = ktime_to_timespec(sk->sk_stamp);
+ if (ts.tv_sec == -1)
+ return -ENOENT;
+ if (ts.tv_sec == 0) {
+ sk->sk_stamp = ktime_get_real();
+ ts = ktime_to_timespec(sk->sk_stamp);
+ }
+ return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestampns);
+
void sock_enable_timestamp(struct sock *sk)
{
if (!sock_flag(sk, SOCK_TIMESTAMP)) {
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index f573eddc603..487f879f5a1 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -727,6 +727,9 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
case SIOCGSTAMP:
return sock_get_timestamp(sk, argp);
+ case SIOCGSTAMPNS:
+ return sock_get_timestampns(sk, argp);
+
case SIOCSIFADDR:
case SIOCGIFADDR:
return ec_dev_ioctl(sock, cmd, argp);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index cf358c84c44..df41856fc60 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -755,6 +755,9 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP:
err = sock_get_timestamp(sk, (struct timeval __user *)arg);
break;
+ case SIOCGSTAMPNS:
+ err = sock_get_timestampns(sk, (struct timespec __user *)arg);
+ break;
case SIOCADDRT:
case SIOCDELRT:
case SIOCRTMSG:
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index fed3758181e..2ff07041795 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -443,6 +443,9 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP:
return sock_get_timestamp(sk, (struct timeval __user *)arg);
+ case SIOCGSTAMPNS:
+ return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
case SIOCADDRT:
case SIOCDELRT:
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index bf9837dd95c..a54e7ef2568 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1209,6 +1209,12 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
release_sock(sk);
return ret;
+ case SIOCGSTAMPNS:
+ lock_sock(sk);
+ ret = sock_get_timestampns(sk, argp);
+ release_sock(sk);
+ return ret;
+
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c